/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 *
 * Version: 5.10.5 (2022-05-25)
 */
;(function() {
	'use strict'

	var __assign = function() {
		__assign =
			Object.assign ||
			function __assign(t) {
				for (var s, i = 1, n = arguments.length; i < n; i++) {
					s = arguments[i]
					for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]
				}
				return t
			}
		return __assign.apply(this, arguments)
	}
	function __rest(s, e) {
		var t = {}
		for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]
		if (s != null && typeof Object.getOwnPropertySymbols === 'function')
			for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
				if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]
			}
		return t
	}
	function __spreadArray(to, from, pack) {
		if (pack || arguments.length === 2)
			for (var i = 0, l = from.length, ar; i < l; i++) {
				if (ar || !(i in from)) {
					if (!ar) ar = Array.prototype.slice.call(from, 0, i)
					ar[i] = from[i]
				}
			}
		return to.concat(ar || Array.prototype.slice.call(from))
	}

	var typeOf = function(x) {
		var t = typeof x
		if (x === null) {
			return 'null'
		} else if (
			t === 'object' &&
			(Array.prototype.isPrototypeOf(x) || (x.constructor && x.constructor.name === 'Array'))
		) {
			return 'array'
		} else if (
			t === 'object' &&
			(String.prototype.isPrototypeOf(x) || (x.constructor && x.constructor.name === 'String'))
		) {
			return 'string'
		} else {
			return t
		}
	}
	var isType$1 = function(type) {
		return function(value) {
			return typeOf(value) === type
		}
	}
	var isSimpleType = function(type) {
		return function(value) {
			return typeof value === type
		}
	}
	var eq$1 = function(t) {
		return function(a) {
			return t === a
		}
	}
	var isString = isType$1('string')
	var isObject = isType$1('object')
	var isArray = isType$1('array')
	var isNull = eq$1(null)
	var isBoolean = isSimpleType('boolean')
	var isUndefined = eq$1(undefined)
	var isNullable = function(a) {
		return a === null || a === undefined
	}
	var isNonNullable = function(a) {
		return !isNullable(a)
	}
	var isFunction = isSimpleType('function')
	var isNumber = isSimpleType('number')

	var noop = function() {}
	var compose = function(fa, fb) {
		return function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			return fa(fb.apply(null, args))
		}
	}
	var compose1 = function(fbc, fab) {
		return function(a) {
			return fbc(fab(a))
		}
	}
	var constant$1 = function(value) {
		return function() {
			return value
		}
	}
	var identity = function(x) {
		return x
	}
	var tripleEquals = function(a, b) {
		return a === b
	}
	function curry(fn) {
		var initialArgs = []
		for (var _i = 1; _i < arguments.length; _i++) {
			initialArgs[_i - 1] = arguments[_i]
		}
		return function() {
			var restArgs = []
			for (var _i = 0; _i < arguments.length; _i++) {
				restArgs[_i] = arguments[_i]
			}
			var all = initialArgs.concat(restArgs)
			return fn.apply(null, all)
		}
	}
	var not = function(f) {
		return function(t) {
			return !f(t)
		}
	}
	var die = function(msg) {
		return function() {
			throw new Error(msg)
		}
	}
	var apply$1 = function(f) {
		return f()
	}
	var never = constant$1(false)
	var always = constant$1(true)

	var none = function() {
		return NONE
	}
	var NONE = (function() {
		var call = function(thunk) {
			return thunk()
		}
		var id = identity
		var me = {
			fold: function(n, _s) {
				return n()
			},
			isSome: never,
			isNone: always,
			getOr: id,
			getOrThunk: call,
			getOrDie: function(msg) {
				throw new Error(msg || 'error: getOrDie called on none.')
			},
			getOrNull: constant$1(null),
			getOrUndefined: constant$1(undefined),
			or: id,
			orThunk: call,
			map: none,
			each: noop,
			bind: none,
			exists: never,
			forall: always,
			filter: function() {
				return none()
			},
			toArray: function() {
				return []
			},
			toString: constant$1('none()')
		}
		return me
	})()
	var some = function(a) {
		var constant_a = constant$1(a)
		var self = function() {
			return me
		}
		var bind = function(f) {
			return f(a)
		}
		var me = {
			fold: function(n, s) {
				return s(a)
			},
			isSome: always,
			isNone: never,
			getOr: constant_a,
			getOrThunk: constant_a,
			getOrDie: constant_a,
			getOrNull: constant_a,
			getOrUndefined: constant_a,
			or: self,
			orThunk: self,
			map: function(f) {
				return some(f(a))
			},
			each: function(f) {
				f(a)
			},
			bind: bind,
			exists: bind,
			forall: bind,
			filter: function(f) {
				return f(a) ? me : NONE
			},
			toArray: function() {
				return [a]
			},
			toString: function() {
				return 'some(' + a + ')'
			}
		}
		return me
	}
	var from = function(value) {
		return value === null || value === undefined ? NONE : some(value)
	}
	var Optional = {
		some: some,
		none: none,
		from: from
	}

	var cached = function(f) {
		var called = false
		var r
		return function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			if (!called) {
				called = true
				r = f.apply(null, args)
			}
			return r
		}
	}

	var DeviceType = function(os, browser, userAgent, mediaMatch) {
		var isiPad = os.isiOS() && /ipad/i.test(userAgent) === true
		var isiPhone = os.isiOS() && !isiPad
		var isMobile = os.isiOS() || os.isAndroid()
		var isTouch = isMobile || mediaMatch('(pointer:coarse)')
		var isTablet = isiPad || (!isiPhone && isMobile && mediaMatch('(min-device-width:768px)'))
		var isPhone = isiPhone || (isMobile && !isTablet)
		var iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false
		var isDesktop = !isPhone && !isTablet && !iOSwebview
		return {
			isiPad: constant$1(isiPad),
			isiPhone: constant$1(isiPhone),
			isTablet: constant$1(isTablet),
			isPhone: constant$1(isPhone),
			isTouch: constant$1(isTouch),
			isAndroid: os.isAndroid,
			isiOS: os.isiOS,
			isWebView: constant$1(iOSwebview),
			isDesktop: constant$1(isDesktop)
		}
	}

	var nativeSlice = Array.prototype.slice
	var nativeIndexOf = Array.prototype.indexOf
	var nativePush = Array.prototype.push
	var rawIndexOf = function(ts, t) {
		return nativeIndexOf.call(ts, t)
	}
	var contains$1 = function(xs, x) {
		return rawIndexOf(xs, x) > -1
	}
	var exists = function(xs, pred) {
		for (var i = 0, len = xs.length; i < len; i++) {
			var x = xs[i]
			if (pred(x, i)) {
				return true
			}
		}
		return false
	}
	var map$2 = function(xs, f) {
		var len = xs.length
		var r = new Array(len)
		for (var i = 0; i < len; i++) {
			var x = xs[i]
			r[i] = f(x, i)
		}
		return r
	}
	var each$1 = function(xs, f) {
		for (var i = 0, len = xs.length; i < len; i++) {
			var x = xs[i]
			f(x, i)
		}
	}
	var eachr = function(xs, f) {
		for (var i = xs.length - 1; i >= 0; i--) {
			var x = xs[i]
			f(x, i)
		}
	}
	var filter$2 = function(xs, pred) {
		var r = []
		for (var i = 0, len = xs.length; i < len; i++) {
			var x = xs[i]
			if (pred(x, i)) {
				r.push(x)
			}
		}
		return r
	}
	var foldr = function(xs, f, acc) {
		eachr(xs, function(x, i) {
			acc = f(acc, x, i)
		})
		return acc
	}
	var foldl = function(xs, f, acc) {
		each$1(xs, function(x, i) {
			acc = f(acc, x, i)
		})
		return acc
	}
	var findUntil = function(xs, pred, until) {
		for (var i = 0, len = xs.length; i < len; i++) {
			var x = xs[i]
			if (pred(x, i)) {
				return Optional.some(x)
			} else if (until(x, i)) {
				break
			}
		}
		return Optional.none()
	}
	var find$2 = function(xs, pred) {
		return findUntil(xs, pred, never)
	}
	var findIndex$1 = function(xs, pred) {
		for (var i = 0, len = xs.length; i < len; i++) {
			var x = xs[i]
			if (pred(x, i)) {
				return Optional.some(i)
			}
		}
		return Optional.none()
	}
	var flatten = function(xs) {
		var r = []
		for (var i = 0, len = xs.length; i < len; ++i) {
			if (!isArray(xs[i])) {
				throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs)
			}
			nativePush.apply(r, xs[i])
		}
		return r
	}
	var bind$3 = function(xs, f) {
		return flatten(map$2(xs, f))
	}
	var forall = function(xs, pred) {
		for (var i = 0, len = xs.length; i < len; ++i) {
			var x = xs[i]
			if (pred(x, i) !== true) {
				return false
			}
		}
		return true
	}
	var reverse = function(xs) {
		var r = nativeSlice.call(xs, 0)
		r.reverse()
		return r
	}
	var difference = function(a1, a2) {
		return filter$2(a1, function(x) {
			return !contains$1(a2, x)
		})
	}
	var pure$2 = function(x) {
		return [x]
	}
	var sort = function(xs, comparator) {
		var copy = nativeSlice.call(xs, 0)
		copy.sort(comparator)
		return copy
	}
	var get$d = function(xs, i) {
		return i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none()
	}
	var head = function(xs) {
		return get$d(xs, 0)
	}
	var findMap = function(arr, f) {
		for (var i = 0; i < arr.length; i++) {
			var r = f(arr[i], i)
			if (r.isSome()) {
				return r
			}
		}
		return Optional.none()
	}

	var firstMatch = function(regexes, s) {
		for (var i = 0; i < regexes.length; i++) {
			var x = regexes[i]
			if (x.test(s)) {
				return x
			}
		}
		return undefined
	}
	var find$1 = function(regexes, agent) {
		var r = firstMatch(regexes, agent)
		if (!r) {
			return {
				major: 0,
				minor: 0
			}
		}
		var group = function(i) {
			return Number(agent.replace(r, '$' + i))
		}
		return nu$8(group(1), group(2))
	}
	var detect$4 = function(versionRegexes, agent) {
		var cleanedAgent = String(agent).toLowerCase()
		if (versionRegexes.length === 0) {
			return unknown$3()
		}
		return find$1(versionRegexes, cleanedAgent)
	}
	var unknown$3 = function() {
		return nu$8(0, 0)
	}
	var nu$8 = function(major, minor) {
		return {
			major: major,
			minor: minor
		}
	}
	var Version = {
		nu: nu$8,
		detect: detect$4,
		unknown: unknown$3
	}

	var detectBrowser$1 = function(browsers, userAgentData) {
		return findMap(userAgentData.brands, function(uaBrand) {
			var lcBrand = uaBrand.brand.toLowerCase()
			return find$2(browsers, function(browser) {
				var _a
				return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase())
			}).map(function(info) {
				return {
					current: info.name,
					version: Version.nu(parseInt(uaBrand.version, 10), 0)
				}
			})
		})
	}

	var detect$3 = function(candidates, userAgent) {
		var agent = String(userAgent).toLowerCase()
		return find$2(candidates, function(candidate) {
			return candidate.search(agent)
		})
	}
	var detectBrowser = function(browsers, userAgent) {
		return detect$3(browsers, userAgent).map(function(browser) {
			var version = Version.detect(browser.versionRegexes, userAgent)
			return {
				current: browser.name,
				version: version
			}
		})
	}
	var detectOs = function(oses, userAgent) {
		return detect$3(oses, userAgent).map(function(os) {
			var version = Version.detect(os.versionRegexes, userAgent)
			return {
				current: os.name,
				version: version
			}
		})
	}

	var checkRange = function(str, substr, start) {
		return substr === '' || (str.length >= substr.length && str.substr(start, start + substr.length) === substr)
	}
	var supplant = function(str, obj) {
		var isStringOrNumber = function(a) {
			var t = typeof a
			return t === 'string' || t === 'number'
		}
		return str.replace(/\$\{([^{}]*)\}/g, function(fullMatch, key) {
			var value = obj[key]
			return isStringOrNumber(value) ? value.toString() : fullMatch
		})
	}
	var contains = function(str, substr) {
		return str.indexOf(substr) !== -1
	}
	var endsWith = function(str, suffix) {
		return checkRange(str, suffix, str.length - suffix.length)
	}
	var blank = function(r) {
		return function(s) {
			return s.replace(r, '')
		}
	}
	var trim = blank(/^\s+|\s+$/g)

	var normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/
	var checkContains = function(target) {
		return function(uastring) {
			return contains(uastring, target)
		}
	}
	var browsers = [
		{
			name: 'Edge',
			versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
			search: function(uastring) {
				return (
					contains(uastring, 'edge/') &&
					contains(uastring, 'chrome') &&
					contains(uastring, 'safari') &&
					contains(uastring, 'applewebkit')
				)
			}
		},
		{
			name: 'Chrome',
			brand: 'Chromium',
			versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/, normalVersionRegex],
			search: function(uastring) {
				return contains(uastring, 'chrome') && !contains(uastring, 'chromeframe')
			}
		},
		{
			name: 'IE',
			versionRegexes: [/.*?msie\ ?([0-9]+)\.([0-9]+).*/, /.*?rv:([0-9]+)\.([0-9]+).*/],
			search: function(uastring) {
				return contains(uastring, 'msie') || contains(uastring, 'trident')
			}
		},
		{
			name: 'Opera',
			versionRegexes: [normalVersionRegex, /.*?opera\/([0-9]+)\.([0-9]+).*/],
			search: checkContains('opera')
		},
		{
			name: 'Firefox',
			versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
			search: checkContains('firefox')
		},
		{
			name: 'Safari',
			versionRegexes: [normalVersionRegex, /.*?cpu os ([0-9]+)_([0-9]+).*/],
			search: function(uastring) {
				return (
					(contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit')
				)
			}
		}
	]
	var oses = [
		{
			name: 'Windows',
			search: checkContains('win'),
			versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
		},
		{
			name: 'iOS',
			search: function(uastring) {
				return contains(uastring, 'iphone') || contains(uastring, 'ipad')
			},
			versionRegexes: [
				/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
				/.*cpu os ([0-9]+)_([0-9]+).*/,
				/.*cpu iphone os ([0-9]+)_([0-9]+).*/
			]
		},
		{
			name: 'Android',
			search: checkContains('android'),
			versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
		},
		{
			name: 'OSX',
			search: checkContains('mac os x'),
			versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
		},
		{
			name: 'Linux',
			search: checkContains('linux'),
			versionRegexes: []
		},
		{
			name: 'Solaris',
			search: checkContains('sunos'),
			versionRegexes: []
		},
		{
			name: 'FreeBSD',
			search: checkContains('freebsd'),
			versionRegexes: []
		},
		{
			name: 'ChromeOS',
			search: checkContains('cros'),
			versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
		}
	]
	var PlatformInfo = {
		browsers: constant$1(browsers),
		oses: constant$1(oses)
	}

	var edge = 'Edge'
	var chrome = 'Chrome'
	var ie = 'IE'
	var opera = 'Opera'
	var firefox = 'Firefox'
	var safari = 'Safari'
	var unknown$2 = function() {
		return nu$7({
			current: undefined,
			version: Version.unknown()
		})
	}
	var nu$7 = function(info) {
		var current = info.current
		var version = info.version
		var isBrowser = function(name) {
			return function() {
				return current === name
			}
		}
		return {
			current: current,
			version: version,
			isEdge: isBrowser(edge),
			isChrome: isBrowser(chrome),
			isIE: isBrowser(ie),
			isOpera: isBrowser(opera),
			isFirefox: isBrowser(firefox),
			isSafari: isBrowser(safari)
		}
	}
	var Browser = {
		unknown: unknown$2,
		nu: nu$7,
		edge: constant$1(edge),
		chrome: constant$1(chrome),
		ie: constant$1(ie),
		opera: constant$1(opera),
		firefox: constant$1(firefox),
		safari: constant$1(safari)
	}

	var windows = 'Windows'
	var ios = 'iOS'
	var android = 'Android'
	var linux = 'Linux'
	var osx = 'OSX'
	var solaris = 'Solaris'
	var freebsd = 'FreeBSD'
	var chromeos = 'ChromeOS'
	var unknown$1 = function() {
		return nu$6({
			current: undefined,
			version: Version.unknown()
		})
	}
	var nu$6 = function(info) {
		var current = info.current
		var version = info.version
		var isOS = function(name) {
			return function() {
				return current === name
			}
		}
		return {
			current: current,
			version: version,
			isWindows: isOS(windows),
			isiOS: isOS(ios),
			isAndroid: isOS(android),
			isOSX: isOS(osx),
			isLinux: isOS(linux),
			isSolaris: isOS(solaris),
			isFreeBSD: isOS(freebsd),
			isChromeOS: isOS(chromeos)
		}
	}
	var OperatingSystem = {
		unknown: unknown$1,
		nu: nu$6,
		windows: constant$1(windows),
		ios: constant$1(ios),
		android: constant$1(android),
		linux: constant$1(linux),
		osx: constant$1(osx),
		solaris: constant$1(solaris),
		freebsd: constant$1(freebsd),
		chromeos: constant$1(chromeos)
	}

	var detect$2 = function(userAgent, userAgentDataOpt, mediaMatch) {
		var browsers = PlatformInfo.browsers()
		var oses = PlatformInfo.oses()
		var browser = userAgentDataOpt
			.bind(function(userAgentData) {
				return detectBrowser$1(browsers, userAgentData)
			})
			.orThunk(function() {
				return detectBrowser(browsers, userAgent)
			})
			.fold(Browser.unknown, Browser.nu)
		var os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu)
		var deviceType = DeviceType(os, browser, userAgent, mediaMatch)
		return {
			browser: browser,
			os: os,
			deviceType: deviceType
		}
	}
	var PlatformDetection = { detect: detect$2 }

	var mediaMatch = function(query) {
		return window.matchMedia(query).matches
	}
	var platform$1 = cached(function() {
		return PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch)
	})
	var detect$1 = function() {
		return platform$1()
	}

	var constant = constant$1
	var touchstart = constant('touchstart')
	var touchmove = constant('touchmove')
	var touchend = constant('touchend')
	var mousedown = constant('mousedown')
	var mousemove = constant('mousemove')
	var mouseup = constant('mouseup')
	var mouseover = constant('mouseover')
	var keydown = constant('keydown')
	var keyup = constant('keyup')
	var input$1 = constant('input')
	var change = constant('change')
	var click = constant('click')
	var transitionend = constant('transitionend')
	var selectstart = constant('selectstart')

	var prefixName = function(name) {
		return constant$1('alloy.' + name)
	}
	var alloy = { tap: prefixName('tap') }
	var focus$4 = prefixName('focus')
	var postBlur = prefixName('blur.post')
	var postPaste = prefixName('paste.post')
	var receive$1 = prefixName('receive')
	var execute$5 = prefixName('execute')
	var focusItem = prefixName('focus.item')
	var tap = alloy.tap
	var longpress = prefixName('longpress')
	var systemInit = prefixName('system.init')
	var attachedToDom = prefixName('system.attached')
	var detachedFromDom = prefixName('system.detached')
	var focusShifted = prefixName('focusmanager.shifted')
	var highlight$1 = prefixName('highlight')
	var dehighlight$1 = prefixName('dehighlight')

	var emit = function(component, event) {
		dispatchWith(component, component.element, event, {})
	}
	var emitWith = function(component, event, properties) {
		dispatchWith(component, component.element, event, properties)
	}
	var emitExecute = function(component) {
		emit(component, execute$5())
	}
	var dispatch = function(component, target, event) {
		dispatchWith(component, target, event, {})
	}
	var dispatchWith = function(component, target, event, properties) {
		var data = __assign({ target: target }, properties)
		component.getSystem().triggerEvent(event, target, data)
	}
	var dispatchEvent = function(component, target, event, simulatedEvent) {
		component.getSystem().triggerEvent(event, target, simulatedEvent.event)
	}
	var dispatchFocus = function(component, target) {
		component.getSystem().triggerFocus(target, component.element)
	}

	var DOCUMENT = 9
	var DOCUMENT_FRAGMENT = 11
	var ELEMENT = 1
	var TEXT = 3

	var fromHtml$2 = function(html, scope) {
		var doc = scope || document
		var div = doc.createElement('div')
		div.innerHTML = html
		if (!div.hasChildNodes() || div.childNodes.length > 1) {
			console.error('HTML does not have a single root node', html)
			throw new Error('HTML must have a single root node')
		}
		return fromDom(div.childNodes[0])
	}
	var fromTag = function(tag, scope) {
		var doc = scope || document
		var node = doc.createElement(tag)
		return fromDom(node)
	}
	var fromText = function(text, scope) {
		var doc = scope || document
		var node = doc.createTextNode(text)
		return fromDom(node)
	}
	var fromDom = function(node) {
		if (node === null || node === undefined) {
			throw new Error('Node cannot be null or undefined')
		}
		return { dom: node }
	}
	var fromPoint = function(docElm, x, y) {
		return Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom)
	}
	var SugarElement = {
		fromHtml: fromHtml$2,
		fromTag: fromTag,
		fromText: fromText,
		fromDom: fromDom,
		fromPoint: fromPoint
	}

	var is$1 = function(element, selector) {
		var dom = element.dom
		if (dom.nodeType !== ELEMENT) {
			return false
		} else {
			var elem = dom
			if (elem.matches !== undefined) {
				return elem.matches(selector)
			} else if (elem.msMatchesSelector !== undefined) {
				return elem.msMatchesSelector(selector)
			} else if (elem.webkitMatchesSelector !== undefined) {
				return elem.webkitMatchesSelector(selector)
			} else if (elem.mozMatchesSelector !== undefined) {
				return elem.mozMatchesSelector(selector)
			} else {
				throw new Error('Browser lacks native selectors')
			}
		}
	}
	var bypassSelector = function(dom) {
		return (
			(dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT) ||
			dom.childElementCount === 0
		)
	}
	var all$2 = function(selector, scope) {
		var base = scope === undefined ? document : scope.dom
		return bypassSelector(base) ? [] : map$2(base.querySelectorAll(selector), SugarElement.fromDom)
	}
	var one = function(selector, scope) {
		var base = scope === undefined ? document : scope.dom
		return bypassSelector(base)
			? Optional.none()
			: Optional.from(base.querySelector(selector)).map(SugarElement.fromDom)
	}

	var eq = function(e1, e2) {
		return e1.dom === e2.dom
	}

	typeof window !== 'undefined' ? window : Function('return this;')()

	var name$1 = function(element) {
		var r = element.dom.nodeName
		return r.toLowerCase()
	}
	var type = function(element) {
		return element.dom.nodeType
	}
	var isType = function(t) {
		return function(element) {
			return type(element) === t
		}
	}
	var isElement = isType(ELEMENT)
	var isText = isType(TEXT)
	var isDocument = isType(DOCUMENT)
	var isDocumentFragment = isType(DOCUMENT_FRAGMENT)

	var owner$2 = function(element) {
		return SugarElement.fromDom(element.dom.ownerDocument)
	}
	var documentOrOwner = function(dos) {
		return isDocument(dos) ? dos : owner$2(dos)
	}
	var defaultView = function(element) {
		return SugarElement.fromDom(documentOrOwner(element).dom.defaultView)
	}
	var parent = function(element) {
		return Optional.from(element.dom.parentNode).map(SugarElement.fromDom)
	}
	var parents = function(element, isRoot) {
		var stop = isFunction(isRoot) ? isRoot : never
		var dom = element.dom
		var ret = []
		while (dom.parentNode !== null && dom.parentNode !== undefined) {
			var rawParent = dom.parentNode
			var p = SugarElement.fromDom(rawParent)
			ret.push(p)
			if (stop(p) === true) {
				break
			} else {
				dom = rawParent
			}
		}
		return ret
	}
	var siblings$2 = function(element) {
		var filterSelf = function(elements) {
			return filter$2(elements, function(x) {
				return !eq(element, x)
			})
		}
		return parent(element)
			.map(children)
			.map(filterSelf)
			.getOr([])
	}
	var nextSibling = function(element) {
		return Optional.from(element.dom.nextSibling).map(SugarElement.fromDom)
	}
	var children = function(element) {
		return map$2(element.dom.childNodes, SugarElement.fromDom)
	}
	var child = function(element, index) {
		var cs = element.dom.childNodes
		return Optional.from(cs[index]).map(SugarElement.fromDom)
	}
	var firstChild = function(element) {
		return child(element, 0)
	}

	var before$1 = function(marker, element) {
		var parent$1 = parent(marker)
		parent$1.each(function(v) {
			v.dom.insertBefore(element.dom, marker.dom)
		})
	}
	var after$2 = function(marker, element) {
		var sibling = nextSibling(marker)
		sibling.fold(
			function() {
				var parent$1 = parent(marker)
				parent$1.each(function(v) {
					append$2(v, element)
				})
			},
			function(v) {
				before$1(v, element)
			}
		)
	}
	var prepend$1 = function(parent, element) {
		var firstChild$1 = firstChild(parent)
		firstChild$1.fold(
			function() {
				append$2(parent, element)
			},
			function(v) {
				parent.dom.insertBefore(element.dom, v.dom)
			}
		)
	}
	var append$2 = function(parent, element) {
		parent.dom.appendChild(element.dom)
	}
	var appendAt = function(parent, element, index) {
		child(parent, index).fold(
			function() {
				append$2(parent, element)
			},
			function(v) {
				before$1(v, element)
			}
		)
	}

	var append$1 = function(parent, elements) {
		each$1(elements, function(x) {
			append$2(parent, x)
		})
	}

	var empty = function(element) {
		element.dom.textContent = ''
		each$1(children(element), function(rogue) {
			remove$7(rogue)
		})
	}
	var remove$7 = function(element) {
		var dom = element.dom
		if (dom.parentNode !== null) {
			dom.parentNode.removeChild(dom)
		}
	}

	var isShadowRoot = function(dos) {
		return isDocumentFragment(dos) && isNonNullable(dos.dom.host)
	}
	var supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode)
	var isSupported$1 = constant$1(supported)
	var getRootNode = supported
		? function(e) {
				return SugarElement.fromDom(e.dom.getRootNode())
		  }
		: documentOrOwner
	var getShadowRoot = function(e) {
		var r = getRootNode(e)
		return isShadowRoot(r) ? Optional.some(r) : Optional.none()
	}
	var getShadowHost = function(e) {
		return SugarElement.fromDom(e.dom.host)
	}
	var getOriginalEventTarget = function(event) {
		if (isSupported$1() && isNonNullable(event.target)) {
			var el = SugarElement.fromDom(event.target)
			if (isElement(el) && isOpenShadowHost(el)) {
				if (event.composed && event.composedPath) {
					var composedPath = event.composedPath()
					if (composedPath) {
						return head(composedPath)
					}
				}
			}
		}
		return Optional.from(event.target)
	}
	var isOpenShadowHost = function(element) {
		return isNonNullable(element.dom.shadowRoot)
	}

	var inBody = function(element) {
		var dom = isText(element) ? element.dom.parentNode : element.dom
		if (dom === undefined || dom === null || dom.ownerDocument === null) {
			return false
		}
		var doc = dom.ownerDocument
		return getShadowRoot(SugarElement.fromDom(dom)).fold(function() {
			return doc.body.contains(dom)
		}, compose1(inBody, getShadowHost))
	}
	var body = function() {
		return getBody(SugarElement.fromDom(document))
	}
	var getBody = function(doc) {
		var b = doc.dom.body
		if (b === null || b === undefined) {
			throw new Error('Body is not available yet')
		}
		return SugarElement.fromDom(b)
	}

	var fireDetaching = function(component) {
		emit(component, detachedFromDom())
		var children = component.components()
		each$1(children, fireDetaching)
	}
	var fireAttaching = function(component) {
		var children = component.components()
		each$1(children, fireAttaching)
		emit(component, attachedToDom())
	}
	var attach$1 = function(parent, child) {
		append$2(parent.element, child.element)
	}
	var detachChildren = function(component) {
		each$1(component.components(), function(childComp) {
			return remove$7(childComp.element)
		})
		empty(component.element)
		component.syncComponents()
	}
	var replaceChildren = function(component, newChildren) {
		var subs = component.components()
		detachChildren(component)
		var deleted = difference(subs, newChildren)
		each$1(deleted, function(comp) {
			fireDetaching(comp)
			component.getSystem().removeFromWorld(comp)
		})
		each$1(newChildren, function(childComp) {
			if (!childComp.getSystem().isConnected()) {
				component.getSystem().addToWorld(childComp)
				attach$1(component, childComp)
				if (inBody(component.element)) {
					fireAttaching(childComp)
				}
			} else {
				attach$1(component, childComp)
			}
			component.syncComponents()
		})
	}

	var attach = function(parent, child) {
		attachWith(parent, child, append$2)
	}
	var attachWith = function(parent, child, insertion) {
		parent.getSystem().addToWorld(child)
		insertion(parent.element, child.element)
		if (inBody(parent.element)) {
			fireAttaching(child)
		}
		parent.syncComponents()
	}
	var doDetach = function(component) {
		fireDetaching(component)
		remove$7(component.element)
		component.getSystem().removeFromWorld(component)
	}
	var detach = function(component) {
		var parent$1 = parent(component.element).bind(function(p) {
			return component
				.getSystem()
				.getByDom(p)
				.toOptional()
		})
		doDetach(component)
		parent$1.each(function(p) {
			p.syncComponents()
		})
	}
	var attachSystemAfter = function(element, guiSystem) {
		attachSystemWith(element, guiSystem, after$2)
	}
	var attachSystemWith = function(element, guiSystem, inserter) {
		inserter(element, guiSystem.element)
		var children$1 = children(guiSystem.element)
		each$1(children$1, function(child) {
			guiSystem.getByDom(child).each(fireAttaching)
		})
	}
	var detachSystem = function(guiSystem) {
		var children$1 = children(guiSystem.element)
		each$1(children$1, function(child) {
			guiSystem.getByDom(child).each(fireDetaching)
		})
		remove$7(guiSystem.element)
	}

	var keys = Object.keys
	var hasOwnProperty = Object.hasOwnProperty
	var each = function(obj, f) {
		var props = keys(obj)
		for (var k = 0, len = props.length; k < len; k++) {
			var i = props[k]
			var x = obj[i]
			f(x, i)
		}
	}
	var map$1 = function(obj, f) {
		return tupleMap(obj, function(x, i) {
			return {
				k: i,
				v: f(x, i)
			}
		})
	}
	var tupleMap = function(obj, f) {
		var r = {}
		each(obj, function(x, i) {
			var tuple = f(x, i)
			r[tuple.k] = tuple.v
		})
		return r
	}
	var objAcc = function(r) {
		return function(x, i) {
			r[i] = x
		}
	}
	var internalFilter = function(obj, pred, onTrue, onFalse) {
		var r = {}
		each(obj, function(x, i) {
			;(pred(x, i) ? onTrue : onFalse)(x, i)
		})
		return r
	}
	var filter$1 = function(obj, pred) {
		var t = {}
		internalFilter(obj, pred, objAcc(t), noop)
		return t
	}
	var mapToArray = function(obj, f) {
		var r = []
		each(obj, function(value, name) {
			r.push(f(value, name))
		})
		return r
	}
	var find = function(obj, pred) {
		var props = keys(obj)
		for (var k = 0, len = props.length; k < len; k++) {
			var i = props[k]
			var x = obj[i]
			if (pred(x, i, obj)) {
				return Optional.some(x)
			}
		}
		return Optional.none()
	}
	var values = function(obj) {
		return mapToArray(obj, identity)
	}
	var get$c = function(obj, key) {
		return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none()
	}
	var has$2 = function(obj, key) {
		return hasOwnProperty.call(obj, key)
	}
	var hasNonNullableKey = function(obj, key) {
		return has$2(obj, key) && obj[key] !== undefined && obj[key] !== null
	}

	var rawSet = function(dom, key, value) {
		if (isString(value) || isBoolean(value) || isNumber(value)) {
			dom.setAttribute(key, value + '')
		} else {
			console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom)
			throw new Error('Attribute value was not simple')
		}
	}
	var set$8 = function(element, key, value) {
		rawSet(element.dom, key, value)
	}
	var setAll$1 = function(element, attrs) {
		var dom = element.dom
		each(attrs, function(v, k) {
			rawSet(dom, k, v)
		})
	}
	var get$b = function(element, key) {
		var v = element.dom.getAttribute(key)
		return v === null ? undefined : v
	}
	var getOpt = function(element, key) {
		return Optional.from(get$b(element, key))
	}
	var has$1 = function(element, key) {
		var dom = element.dom
		return dom && dom.hasAttribute ? dom.hasAttribute(key) : false
	}
	var remove$6 = function(element, key) {
		element.dom.removeAttribute(key)
	}

	var read$2 = function(element, attr) {
		var value = get$b(element, attr)
		return value === undefined || value === '' ? [] : value.split(' ')
	}
	var add$3 = function(element, attr, id) {
		var old = read$2(element, attr)
		var nu = old.concat([id])
		set$8(element, attr, nu.join(' '))
		return true
	}
	var remove$5 = function(element, attr, id) {
		var nu = filter$2(read$2(element, attr), function(v) {
			return v !== id
		})
		if (nu.length > 0) {
			set$8(element, attr, nu.join(' '))
		} else {
			remove$6(element, attr)
		}
		return false
	}

	var supports = function(element) {
		return element.dom.classList !== undefined
	}
	var get$a = function(element) {
		return read$2(element, 'class')
	}
	var add$2 = function(element, clazz) {
		return add$3(element, 'class', clazz)
	}
	var remove$4 = function(element, clazz) {
		return remove$5(element, 'class', clazz)
	}

	var add$1 = function(element, clazz) {
		if (supports(element)) {
			element.dom.classList.add(clazz)
		} else {
			add$2(element, clazz)
		}
	}
	var cleanClass = function(element) {
		var classList = supports(element) ? element.dom.classList : get$a(element)
		if (classList.length === 0) {
			remove$6(element, 'class')
		}
	}
	var remove$3 = function(element, clazz) {
		if (supports(element)) {
			var classList = element.dom.classList
			classList.remove(clazz)
		} else {
			remove$4(element, clazz)
		}
		cleanClass(element)
	}
	var has = function(element, clazz) {
		return supports(element) && element.dom.classList.contains(clazz)
	}

	var swap = function(element, addCls, removeCls) {
		remove$3(element, removeCls)
		add$1(element, addCls)
	}
	var toAlpha = function(component, swapConfig, _swapState) {
		swap(component.element, swapConfig.alpha, swapConfig.omega)
	}
	var toOmega = function(component, swapConfig, _swapState) {
		swap(component.element, swapConfig.omega, swapConfig.alpha)
	}
	var clear$1 = function(component, swapConfig, _swapState) {
		remove$3(component.element, swapConfig.alpha)
		remove$3(component.element, swapConfig.omega)
	}
	var isAlpha = function(component, swapConfig, _swapState) {
		return has(component.element, swapConfig.alpha)
	}
	var isOmega = function(component, swapConfig, _swapState) {
		return has(component.element, swapConfig.omega)
	}

	var SwapApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		toAlpha: toAlpha,
		toOmega: toOmega,
		isAlpha: isAlpha,
		isOmega: isOmega,
		clear: clear$1
	})

	var value$2 = function(o) {
		var or = function(_opt) {
			return value$2(o)
		}
		var orThunk = function(_f) {
			return value$2(o)
		}
		var map = function(f) {
			return value$2(f(o))
		}
		var mapError = function(_f) {
			return value$2(o)
		}
		var each = function(f) {
			f(o)
		}
		var bind = function(f) {
			return f(o)
		}
		var fold = function(_, onValue) {
			return onValue(o)
		}
		var exists = function(f) {
			return f(o)
		}
		var forall = function(f) {
			return f(o)
		}
		var toOptional = function() {
			return Optional.some(o)
		}
		return {
			isValue: always,
			isError: never,
			getOr: constant$1(o),
			getOrThunk: constant$1(o),
			getOrDie: constant$1(o),
			or: or,
			orThunk: orThunk,
			fold: fold,
			map: map,
			mapError: mapError,
			each: each,
			bind: bind,
			exists: exists,
			forall: forall,
			toOptional: toOptional
		}
	}
	var error = function(message) {
		var getOrThunk = function(f) {
			return f()
		}
		var getOrDie = function() {
			return die(String(message))()
		}
		var or = identity
		var orThunk = function(f) {
			return f()
		}
		var map = function(_f) {
			return error(message)
		}
		var mapError = function(f) {
			return error(f(message))
		}
		var bind = function(_f) {
			return error(message)
		}
		var fold = function(onError, _) {
			return onError(message)
		}
		return {
			isValue: never,
			isError: always,
			getOr: identity,
			getOrThunk: getOrThunk,
			getOrDie: getOrDie,
			or: or,
			orThunk: orThunk,
			fold: fold,
			map: map,
			mapError: mapError,
			each: noop,
			bind: bind,
			exists: never,
			forall: always,
			toOptional: Optional.none
		}
	}
	var fromOption = function(opt, err) {
		return opt.fold(function() {
			return error(err)
		}, value$2)
	}
	var Result = {
		value: value$2,
		error: error,
		fromOption: fromOption
	}

	var SimpleResultType
	;(function(SimpleResultType) {
		SimpleResultType[(SimpleResultType['Error'] = 0)] = 'Error'
		SimpleResultType[(SimpleResultType['Value'] = 1)] = 'Value'
	})(SimpleResultType || (SimpleResultType = {}))
	var fold$1 = function(res, onError, onValue) {
		return res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue)
	}
	var partition$1 = function(results) {
		var values = []
		var errors = []
		each$1(results, function(obj) {
			fold$1(
				obj,
				function(err) {
					return errors.push(err)
				},
				function(val) {
					return values.push(val)
				}
			)
		})
		return {
			values: values,
			errors: errors
		}
	}
	var mapError = function(res, f) {
		if (res.stype === SimpleResultType.Error) {
			return {
				stype: SimpleResultType.Error,
				serror: f(res.serror)
			}
		} else {
			return res
		}
	}
	var map = function(res, f) {
		if (res.stype === SimpleResultType.Value) {
			return {
				stype: SimpleResultType.Value,
				svalue: f(res.svalue)
			}
		} else {
			return res
		}
	}
	var bind$2 = function(res, f) {
		if (res.stype === SimpleResultType.Value) {
			return f(res.svalue)
		} else {
			return res
		}
	}
	var bindError = function(res, f) {
		if (res.stype === SimpleResultType.Error) {
			return f(res.serror)
		} else {
			return res
		}
	}
	var svalue = function(v) {
		return {
			stype: SimpleResultType.Value,
			svalue: v
		}
	}
	var serror = function(e) {
		return {
			stype: SimpleResultType.Error,
			serror: e
		}
	}
	var toResult$1 = function(res) {
		return fold$1(res, Result.error, Result.value)
	}
	var fromResult = function(res) {
		return res.fold(serror, svalue)
	}
	var SimpleResult = {
		fromResult: fromResult,
		toResult: toResult$1,
		svalue: svalue,
		partition: partition$1,
		serror: serror,
		bind: bind$2,
		bindError: bindError,
		map: map,
		mapError: mapError,
		fold: fold$1
	}

	var field$3 = function(key, newKey, presence, prop) {
		return {
			tag: 'field',
			key: key,
			newKey: newKey,
			presence: presence,
			prop: prop
		}
	}
	var customField$1 = function(newKey, instantiator) {
		return {
			tag: 'custom',
			newKey: newKey,
			instantiator: instantiator
		}
	}
	var fold = function(value, ifField, ifCustom) {
		switch (value.tag) {
			case 'field':
				return ifField(value.key, value.newKey, value.presence, value.prop)
			case 'custom':
				return ifCustom(value.newKey, value.instantiator)
		}
	}

	var shallow$1 = function(old, nu) {
		return nu
	}
	var deep = function(old, nu) {
		var bothObjects = isObject(old) && isObject(nu)
		return bothObjects ? deepMerge(old, nu) : nu
	}
	var baseMerge = function(merger) {
		return function() {
			var objects = []
			for (var _i = 0; _i < arguments.length; _i++) {
				objects[_i] = arguments[_i]
			}
			if (objects.length === 0) {
				throw new Error("Can't merge zero objects")
			}
			var ret = {}
			for (var j = 0; j < objects.length; j++) {
				var curObject = objects[j]
				for (var key in curObject) {
					if (has$2(curObject, key)) {
						ret[key] = merger(ret[key], curObject[key])
					}
				}
			}
			return ret
		}
	}
	var deepMerge = baseMerge(deep)
	var merge$1 = baseMerge(shallow$1)

	var required$2 = function() {
		return {
			tag: 'required',
			process: {}
		}
	}
	var defaultedThunk = function(fallbackThunk) {
		return {
			tag: 'defaultedThunk',
			process: fallbackThunk
		}
	}
	var defaulted$1 = function(fallback) {
		return defaultedThunk(constant$1(fallback))
	}
	var asOption = function() {
		return {
			tag: 'option',
			process: {}
		}
	}
	var mergeWithThunk = function(baseThunk) {
		return {
			tag: 'mergeWithThunk',
			process: baseThunk
		}
	}
	var mergeWith = function(base) {
		return mergeWithThunk(constant$1(base))
	}

	var mergeValues$1 = function(values, base) {
		return values.length > 0
			? SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values)))
			: SimpleResult.svalue(base)
	}
	var mergeErrors$1 = function(errors) {
		return compose(SimpleResult.serror, flatten)(errors)
	}
	var consolidateObj = function(objects, base) {
		var partition = SimpleResult.partition(objects)
		return partition.errors.length > 0 ? mergeErrors$1(partition.errors) : mergeValues$1(partition.values, base)
	}
	var consolidateArr = function(objects) {
		var partitions = SimpleResult.partition(objects)
		return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values)
	}
	var ResultCombine = {
		consolidateObj: consolidateObj,
		consolidateArr: consolidateArr
	}

	var formatObj = function(input) {
		return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2)
	}
	var formatErrors = function(errors) {
		var es =
			errors.length > 10
				? errors.slice(0, 10).concat([
						{
							path: [],
							getErrorInfo: constant$1('... (only showing first ten failures)')
						}
				  ])
				: errors
		return map$2(es, function(e) {
			return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo()
		})
	}

	var nu$5 = function(path, getErrorInfo) {
		return SimpleResult.serror([
			{
				path: path,
				getErrorInfo: getErrorInfo
			}
		])
	}
	var missingRequired = function(path, key, obj) {
		return nu$5(path, function() {
			return 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj)
		})
	}
	var missingKey = function(path, key) {
		return nu$5(path, function() {
			return 'Choice schema did not contain choice key: "' + key + '"'
		})
	}
	var missingBranch = function(path, branches, branch) {
		return nu$5(path, function() {
			return 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches)
		})
	}
	var unsupportedFields = function(path, unsupported) {
		return nu$5(path, function() {
			return 'There are unsupported fields: [' + unsupported.join(', ') + '] specified'
		})
	}
	var custom = function(path, err) {
		return nu$5(path, constant$1(err))
	}

	var value$1 = function(validator) {
		var extract = function(path, val) {
			return SimpleResult.bindError(validator(val), function(err) {
				return custom(path, err)
			})
		}
		var toString = constant$1('val')
		return {
			extract: extract,
			toString: toString
		}
	}
	var anyValue$1 = value$1(SimpleResult.svalue)

	var requiredAccess = function(path, obj, key, bundle) {
		return get$c(obj, key).fold(function() {
			return missingRequired(path, key, obj)
		}, bundle)
	}
	var fallbackAccess = function(obj, key, fallback, bundle) {
		var v = get$c(obj, key).getOrThunk(function() {
			return fallback(obj)
		})
		return bundle(v)
	}
	var optionAccess = function(obj, key, bundle) {
		return bundle(get$c(obj, key))
	}
	var optionDefaultedAccess = function(obj, key, fallback, bundle) {
		var opt = get$c(obj, key).map(function(val) {
			return val === true ? fallback(obj) : val
		})
		return bundle(opt)
	}
	var extractField = function(field, path, obj, key, prop) {
		var bundle = function(av) {
			return prop.extract(path.concat([key]), av)
		}
		var bundleAsOption = function(optValue) {
			return optValue.fold(
				function() {
					return SimpleResult.svalue(Optional.none())
				},
				function(ov) {
					var result = prop.extract(path.concat([key]), ov)
					return SimpleResult.map(result, Optional.some)
				}
			)
		}
		switch (field.tag) {
			case 'required':
				return requiredAccess(path, obj, key, bundle)
			case 'defaultedThunk':
				return fallbackAccess(obj, key, field.process, bundle)
			case 'option':
				return optionAccess(obj, key, bundleAsOption)
			case 'defaultedOptionThunk':
				return optionDefaultedAccess(obj, key, field.process, bundleAsOption)
			case 'mergeWithThunk': {
				return fallbackAccess(obj, key, constant$1({}), function(v) {
					var result = deepMerge(field.process(obj), v)
					return bundle(result)
				})
			}
		}
	}
	var extractFields = function(path, obj, fields) {
		var success = {}
		var errors = []
		for (var _i = 0, fields_1 = fields; _i < fields_1.length; _i++) {
			var field = fields_1[_i]
			fold(
				field,
				function(key, newKey, presence, prop) {
					var result = extractField(presence, path, obj, key, prop)
					SimpleResult.fold(
						result,
						function(err) {
							errors.push.apply(errors, err)
						},
						function(res) {
							success[newKey] = res
						}
					)
				},
				function(newKey, instantiator) {
					success[newKey] = instantiator(obj)
				}
			)
		}
		return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success)
	}
	var getSetKeys = function(obj) {
		return keys(filter$1(obj, isNonNullable))
	}
	var objOfOnly = function(fields) {
		var delegate = objOf(fields)
		var fieldNames = foldr(
			fields,
			function(acc, value) {
				return fold(
					value,
					function(key) {
						var _a
						return deepMerge(acc, ((_a = {}), (_a[key] = true), _a))
					},
					constant$1(acc)
				)
			},
			{}
		)
		var extract = function(path, o) {
			var keys = isBoolean(o) ? [] : getSetKeys(o)
			var extra = filter$2(keys, function(k) {
				return !hasNonNullableKey(fieldNames, k)
			})
			return extra.length === 0 ? delegate.extract(path, o) : unsupportedFields(path, extra)
		}
		return {
			extract: extract,
			toString: delegate.toString
		}
	}
	var objOf = function(values) {
		var extract = function(path, o) {
			return extractFields(path, o, values)
		}
		var toString = function() {
			var fieldStrings = map$2(values, function(value) {
				return fold(
					value,
					function(key, _okey, _presence, prop) {
						return key + ' -> ' + prop.toString()
					},
					function(newKey, _instantiator) {
						return 'state(' + newKey + ')'
					}
				)
			})
			return 'obj{\n' + fieldStrings.join('\n') + '}'
		}
		return {
			extract: extract,
			toString: toString
		}
	}
	var arrOf = function(prop) {
		var extract = function(path, array) {
			var results = map$2(array, function(a, i) {
				return prop.extract(path.concat(['[' + i + ']']), a)
			})
			return ResultCombine.consolidateArr(results)
		}
		var toString = function() {
			return 'array(' + prop.toString() + ')'
		}
		return {
			extract: extract,
			toString: toString
		}
	}
	var setOf$1 = function(validator, prop) {
		var validateKeys = function(path, keys) {
			return arrOf(value$1(validator)).extract(path, keys)
		}
		var extract = function(path, o) {
			var keys$1 = keys(o)
			var validatedKeys = validateKeys(path, keys$1)
			return SimpleResult.bind(validatedKeys, function(validKeys) {
				var schema = map$2(validKeys, function(vk) {
					return field$3(vk, vk, required$2(), prop)
				})
				return objOf(schema).extract(path, o)
			})
		}
		var toString = function() {
			return 'setOf(' + prop.toString() + ')'
		}
		return {
			extract: extract,
			toString: toString
		}
	}

	var anyValue = constant$1(anyValue$1)
	var typedValue = function(validator, expectedType) {
		return value$1(function(a) {
			var actualType = typeof a
			return validator(a)
				? SimpleResult.svalue(a)
				: SimpleResult.serror('Expected type: ' + expectedType + ' but got: ' + actualType)
		})
	}
	var functionProcessor = typedValue(isFunction, 'function')

	var chooseFrom = function(path, input, branches, ch) {
		var fields = get$c(branches, ch)
		return fields.fold(
			function() {
				return missingBranch(path, branches, ch)
			},
			function(vp) {
				return vp.extract(path.concat(['branch: ' + ch]), input)
			}
		)
	}
	var choose$2 = function(key, branches) {
		var extract = function(path, input) {
			var choice = get$c(input, key)
			return choice.fold(
				function() {
					return missingKey(path, key)
				},
				function(chosen) {
					return chooseFrom(path, input, branches, chosen)
				}
			)
		}
		var toString = function() {
			return 'chooseOn(' + key + '). Possible values: ' + keys(branches)
		}
		return {
			extract: extract,
			toString: toString
		}
	}

	var valueOf = function(validator) {
		return value$1(function(v) {
			return validator(v).fold(SimpleResult.serror, SimpleResult.svalue)
		})
	}
	var setOf = function(validator, prop) {
		return setOf$1(function(v) {
			return SimpleResult.fromResult(validator(v))
		}, prop)
	}
	var extractValue = function(label, prop, obj) {
		var res = prop.extract([label], obj)
		return SimpleResult.mapError(res, function(errs) {
			return {
				input: obj,
				errors: errs
			}
		})
	}
	var asRaw = function(label, prop, obj) {
		return SimpleResult.toResult(extractValue(label, prop, obj))
	}
	var getOrDie = function(extraction) {
		return extraction.fold(function(errInfo) {
			throw new Error(formatError(errInfo))
		}, identity)
	}
	var asRawOrDie$1 = function(label, prop, obj) {
		return getOrDie(asRaw(label, prop, obj))
	}
	var formatError = function(errInfo) {
		return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input)
	}
	var choose$1 = function(key, branches) {
		return choose$2(key, map$1(branches, objOf))
	}

	var field$2 = field$3
	var customField = customField$1
	var required$1 = function(key) {
		return field$2(key, key, required$2(), anyValue())
	}
	var requiredOf = function(key, schema) {
		return field$2(key, key, required$2(), schema)
	}
	var forbid = function(key, message) {
		return field$2(
			key,
			key,
			asOption(),
			value$1(function(_v) {
				return SimpleResult.serror('The field: ' + key + ' is forbidden. ' + message)
			})
		)
	}
	var requiredObjOf = function(key, objSchema) {
		return field$2(key, key, required$2(), objOf(objSchema))
	}
	var option = function(key) {
		return field$2(key, key, asOption(), anyValue())
	}
	var optionOf = function(key, schema) {
		return field$2(key, key, asOption(), schema)
	}
	var optionObjOf = function(key, objSchema) {
		return optionOf(key, objOf(objSchema))
	}
	var optionObjOfOnly = function(key, objSchema) {
		return optionOf(key, objOfOnly(objSchema))
	}
	var defaulted = function(key, fallback) {
		return field$2(key, key, defaulted$1(fallback), anyValue())
	}
	var defaultedOf = function(key, fallback, schema) {
		return field$2(key, key, defaulted$1(fallback), schema)
	}
	var defaultedFunction = function(key, fallback) {
		return defaultedOf(key, fallback, functionProcessor)
	}
	var defaultedObjOf = function(key, fallback, objSchema) {
		return defaultedOf(key, fallback, objOf(objSchema))
	}

	var SwapSchema = [required$1('alpha'), required$1('omega')]

	var generate$5 = function(cases) {
		if (!isArray(cases)) {
			throw new Error('cases must be an array')
		}
		if (cases.length === 0) {
			throw new Error('there must be at least one case')
		}
		var constructors = []
		var adt = {}
		each$1(cases, function(acase, count) {
			var keys$1 = keys(acase)
			if (keys$1.length !== 1) {
				throw new Error('one and only one name per case')
			}
			var key = keys$1[0]
			var value = acase[key]
			if (adt[key] !== undefined) {
				throw new Error('duplicate key detected:' + key)
			} else if (key === 'cata') {
				throw new Error('cannot have a case named cata (sorry)')
			} else if (!isArray(value)) {
				throw new Error('case arguments must be an array')
			}
			constructors.push(key)
			adt[key] = function() {
				var args = []
				for (var _i = 0; _i < arguments.length; _i++) {
					args[_i] = arguments[_i]
				}
				var argLength = args.length
				if (argLength !== value.length) {
					throw new Error(
						'Wrong number of arguments to case ' +
							key +
							'. Expected ' +
							value.length +
							' (' +
							value +
							'), got ' +
							argLength
					)
				}
				var match = function(branches) {
					var branchKeys = keys(branches)
					if (constructors.length !== branchKeys.length) {
						throw new Error(
							'Wrong number of arguments to match. Expected: ' +
								constructors.join(',') +
								'\nActual: ' +
								branchKeys.join(',')
						)
					}
					var allReqd = forall(constructors, function(reqKey) {
						return contains$1(branchKeys, reqKey)
					})
					if (!allReqd) {
						throw new Error(
							'Not all branches were specified when using match. Specified: ' +
								branchKeys.join(', ') +
								'\nRequired: ' +
								constructors.join(', ')
						)
					}
					return branches[key].apply(null, args)
				}
				return {
					fold: function() {
						var foldArgs = []
						for (var _i = 0; _i < arguments.length; _i++) {
							foldArgs[_i] = arguments[_i]
						}
						if (foldArgs.length !== cases.length) {
							throw new Error(
								'Wrong number of arguments to fold. Expected ' +
									cases.length +
									', got ' +
									foldArgs.length
							)
						}
						var target = foldArgs[count]
						return target.apply(null, args)
					},
					match: match,
					log: function(label) {
						console.log(label, {
							constructors: constructors,
							constructor: key,
							params: args
						})
					}
				}
			}
		})
		return adt
	}
	var Adt = { generate: generate$5 }

	Adt.generate([
		{
			bothErrors: ['error1', 'error2']
		},
		{
			firstError: ['error1', 'value2']
		},
		{
			secondError: ['value1', 'error2']
		},
		{
			bothValues: ['value1', 'value2']
		}
	])
	var partition = function(results) {
		var errors = []
		var values = []
		each$1(results, function(result) {
			result.fold(
				function(err) {
					errors.push(err)
				},
				function(value) {
					values.push(value)
				}
			)
		})
		return {
			errors: errors,
			values: values
		}
	}

	var exclude$1 = function(obj, fields) {
		var r = {}
		each(obj, function(v, k) {
			if (!contains$1(fields, k)) {
				r[k] = v
			}
		})
		return r
	}

	var wrap$1 = function(key, value) {
		var _a
		return (_a = {}), (_a[key] = value), _a
	}
	var wrapAll$1 = function(keyvalues) {
		var r = {}
		each$1(keyvalues, function(kv) {
			r[kv.key] = kv.value
		})
		return r
	}

	var exclude = function(obj, fields) {
		return exclude$1(obj, fields)
	}
	var wrap = function(key, value) {
		return wrap$1(key, value)
	}
	var wrapAll = function(keyvalues) {
		return wrapAll$1(keyvalues)
	}
	var mergeValues = function(values, base) {
		return values.length === 0
			? Result.value(base)
			: Result.value(deepMerge(base, merge$1.apply(undefined, values)))
	}
	var mergeErrors = function(errors) {
		return Result.error(flatten(errors))
	}
	var consolidate = function(objs, base) {
		var partitions = partition(objs)
		return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base)
	}

	var is = function(lhs, rhs, comparator) {
		if (comparator === void 0) {
			comparator = tripleEquals
		}
		return lhs.exists(function(left) {
			return comparator(left, rhs)
		})
	}
	var cat = function(arr) {
		var r = []
		var push = function(x) {
			r.push(x)
		}
		for (var i = 0; i < arr.length; i++) {
			arr[i].each(push)
		}
		return r
	}
	var sequence = function(arr) {
		var r = []
		for (var i = 0; i < arr.length; i++) {
			var x = arr[i]
			if (x.isSome()) {
				r.push(x.getOrDie())
			} else {
				return Optional.none()
			}
		}
		return Optional.some(r)
	}
	var lift2 = function(oa, ob, f) {
		return oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none()
	}
	var someIf = function(b, a) {
		return b ? Optional.some(a) : Optional.none()
	}

	var ensureIsRoot = function(isRoot) {
		return isFunction(isRoot) ? isRoot : never
	}
	var ancestor$2 = function(scope, transform, isRoot) {
		var element = scope.dom
		var stop = ensureIsRoot(isRoot)
		while (element.parentNode) {
			element = element.parentNode
			var el = SugarElement.fromDom(element)
			var transformed = transform(el)
			if (transformed.isSome()) {
				return transformed
			} else if (stop(el)) {
				break
			}
		}
		return Optional.none()
	}
	var closest$3 = function(scope, transform, isRoot) {
		var current = transform(scope)
		var stop = ensureIsRoot(isRoot)
		return current.orThunk(function() {
			return stop(scope) ? Optional.none() : ancestor$2(scope, transform, stop)
		})
	}

	var isSource = function(component, simulatedEvent) {
		return eq(component.element, simulatedEvent.event.target)
	}

	var defaultEventHandler = {
		can: always,
		abort: never,
		run: noop
	}
	var nu$4 = function(parts) {
		if (
			!hasNonNullableKey(parts, 'can') &&
			!hasNonNullableKey(parts, 'abort') &&
			!hasNonNullableKey(parts, 'run')
		) {
			throw new Error(
				'EventHandler defined by: ' + JSON.stringify(parts, null, 2) + ' does not have can, abort, or run!'
			)
		}
		return __assign(__assign({}, defaultEventHandler), parts)
	}
	var all$1 = function(handlers, f) {
		return function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			return foldl(
				handlers,
				function(acc, handler) {
					return acc && f(handler).apply(undefined, args)
				},
				true
			)
		}
	}
	var any = function(handlers, f) {
		return function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			return foldl(
				handlers,
				function(acc, handler) {
					return acc || f(handler).apply(undefined, args)
				},
				false
			)
		}
	}
	var read$1 = function(handler) {
		return isFunction(handler)
			? {
					can: always,
					abort: never,
					run: handler
			  }
			: handler
	}
	var fuse$1 = function(handlers) {
		var can = all$1(handlers, function(handler) {
			return handler.can
		})
		var abort = any(handlers, function(handler) {
			return handler.abort
		})
		var run = function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			each$1(handlers, function(handler) {
				handler.run.apply(undefined, args)
			})
		}
		return {
			can: can,
			abort: abort,
			run: run
		}
	}

	var derive$3 = function(configs) {
		return wrapAll(configs)
	}
	var abort = function(name, predicate) {
		return {
			key: name,
			value: nu$4({ abort: predicate })
		}
	}
	var can = function(name, predicate) {
		return {
			key: name,
			value: nu$4({ can: predicate })
		}
	}
	var run = function(name, handler) {
		return {
			key: name,
			value: nu$4({ run: handler })
		}
	}
	var runActionExtra = function(name, action, extra) {
		return {
			key: name,
			value: nu$4({
				run: function(component, simulatedEvent) {
					action.apply(undefined, [component, simulatedEvent].concat(extra))
				}
			})
		}
	}
	var runOnName = function(name) {
		return function(handler) {
			return run(name, handler)
		}
	}
	var runOnSourceName = function(name) {
		return function(handler) {
			return {
				key: name,
				value: nu$4({
					run: function(component, simulatedEvent) {
						if (isSource(component, simulatedEvent)) {
							handler(component, simulatedEvent)
						}
					}
				})
			}
		}
	}
	var redirectToUid = function(name, uid) {
		return run(name, function(component, simulatedEvent) {
			component
				.getSystem()
				.getByUid(uid)
				.each(function(redirectee) {
					dispatchEvent(redirectee, redirectee.element, name, simulatedEvent)
				})
		})
	}
	var redirectToPart = function(name, detail, partName) {
		var uid = detail.partUids[partName]
		return redirectToUid(name, uid)
	}
	var cutter = function(name) {
		return run(name, function(component, simulatedEvent) {
			simulatedEvent.cut()
		})
	}
	var stopper = function(name) {
		return run(name, function(component, simulatedEvent) {
			simulatedEvent.stop()
		})
	}
	var runOnSource = function(name, f) {
		return runOnSourceName(name)(f)
	}
	var runOnAttached = runOnSourceName(attachedToDom())
	var runOnDetached = runOnSourceName(detachedFromDom())
	var runOnInit = runOnSourceName(systemInit())
	var runOnExecute = runOnName(execute$5())

	var markAsBehaviourApi = function(f, apiName, apiFunction) {
		var delegate = apiFunction.toString()
		var endIndex = delegate.indexOf(')') + 1
		var openBracketIndex = delegate.indexOf('(')
		var parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/)
		f.toFunctionAnnotation = function() {
			return {
				name: apiName,
				parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
			}
		}
		return f
	}
	var cleanParameters = function(parameters) {
		return map$2(parameters, function(p) {
			return endsWith(p, '/*') ? p.substring(0, p.length - '/*'.length) : p
		})
	}
	var markAsExtraApi = function(f, extraName) {
		var delegate = f.toString()
		var endIndex = delegate.indexOf(')') + 1
		var openBracketIndex = delegate.indexOf('(')
		var parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/)
		f.toFunctionAnnotation = function() {
			return {
				name: extraName,
				parameters: cleanParameters(parameters)
			}
		}
		return f
	}
	var markAsSketchApi = function(f, apiFunction) {
		var delegate = apiFunction.toString()
		var endIndex = delegate.indexOf(')') + 1
		var openBracketIndex = delegate.indexOf('(')
		var parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/)
		f.toFunctionAnnotation = function() {
			return {
				name: 'OVERRIDE',
				parameters: cleanParameters(parameters.slice(1))
			}
		}
		return f
	}

	var nu$3 = function(s) {
		return {
			classes: isUndefined(s.classes) ? [] : s.classes,
			attributes: isUndefined(s.attributes) ? {} : s.attributes,
			styles: isUndefined(s.styles) ? {} : s.styles
		}
	}
	var merge = function(defnA, mod) {
		return __assign(__assign({}, defnA), {
			attributes: __assign(__assign({}, defnA.attributes), mod.attributes),
			styles: __assign(__assign({}, defnA.styles), mod.styles),
			classes: defnA.classes.concat(mod.classes)
		})
	}

	var executeEvent = function(bConfig, bState, executor) {
		return runOnExecute(function(component) {
			executor(component, bConfig, bState)
		})
	}
	var loadEvent = function(bConfig, bState, f) {
		return runOnInit(function(component, _simulatedEvent) {
			f(component, bConfig, bState)
		})
	}
	var create$6 = function(schema, name, active, apis, extra, state) {
		var configSchema = objOfOnly(schema)
		var schemaSchema = optionObjOf(name, [optionObjOfOnly('config', schema)])
		return doCreate(configSchema, schemaSchema, name, active, apis, extra, state)
	}
	var createModes$1 = function(modes, name, active, apis, extra, state) {
		var configSchema = modes
		var schemaSchema = optionObjOf(name, [optionOf('config', modes)])
		return doCreate(configSchema, schemaSchema, name, active, apis, extra, state)
	}
	var wrapApi = function(bName, apiFunction, apiName) {
		var f = function(component) {
			var rest = []
			for (var _i = 1; _i < arguments.length; _i++) {
				rest[_i - 1] = arguments[_i]
			}
			var args = [component].concat(rest)
			return component.config({ name: constant$1(bName) }).fold(
				function() {
					throw new Error(
						'We could not find any behaviour configuration for: ' + bName + '. Using API: ' + apiName
					)
				},
				function(info) {
					var rest = Array.prototype.slice.call(args, 1)
					return apiFunction.apply(undefined, [component, info.config, info.state].concat(rest))
				}
			)
		}
		return markAsBehaviourApi(f, apiName, apiFunction)
	}
	var revokeBehaviour = function(name) {
		return {
			key: name,
			value: undefined
		}
	}
	var doCreate = function(configSchema, schemaSchema, name, active, apis, extra, state) {
		var getConfig = function(info) {
			return hasNonNullableKey(info, name) ? info[name]() : Optional.none()
		}
		var wrappedApis = map$1(apis, function(apiF, apiName) {
			return wrapApi(name, apiF, apiName)
		})
		var wrappedExtra = map$1(extra, function(extraF, extraName) {
			return markAsExtraApi(extraF, extraName)
		})
		var me = __assign(__assign(__assign({}, wrappedExtra), wrappedApis), {
			revoke: curry(revokeBehaviour, name),
			config: function(spec) {
				var prepared = asRawOrDie$1(name + '-config', configSchema, spec)
				return {
					key: name,
					value: {
						config: prepared,
						me: me,
						configAsRaw: cached(function() {
							return asRawOrDie$1(name + '-config', configSchema, spec)
						}),
						initialConfig: spec,
						state: state
					}
				}
			},
			schema: constant$1(schemaSchema),
			exhibit: function(info, base) {
				return lift2(getConfig(info), get$c(active, 'exhibit'), function(behaviourInfo, exhibitor) {
					return exhibitor(base, behaviourInfo.config, behaviourInfo.state)
				}).getOrThunk(function() {
					return nu$3({})
				})
			},
			name: constant$1(name),
			handlers: function(info) {
				return getConfig(info)
					.map(function(behaviourInfo) {
						var getEvents = get$c(active, 'events').getOr(function() {
							return {}
						})
						return getEvents(behaviourInfo.config, behaviourInfo.state)
					})
					.getOr({})
			}
		})
		return me
	}

	var NoState = {
		init: function() {
			return nu$2({ readState: constant$1('No State required') })
		}
	}
	var nu$2 = function(spec) {
		return spec
	}

	var derive$2 = function(capabilities) {
		return wrapAll(capabilities)
	}
	var simpleSchema = objOfOnly([
		required$1('fields'),
		required$1('name'),
		defaulted('active', {}),
		defaulted('apis', {}),
		defaulted('state', NoState),
		defaulted('extra', {})
	])
	var create$5 = function(data) {
		var value = asRawOrDie$1('Creating behaviour: ' + data.name, simpleSchema, data)
		return create$6(value.fields, value.name, value.active, value.apis, value.extra, value.state)
	}
	var modeSchema = objOfOnly([
		required$1('branchKey'),
		required$1('branches'),
		required$1('name'),
		defaulted('active', {}),
		defaulted('apis', {}),
		defaulted('state', NoState),
		defaulted('extra', {})
	])
	var createModes = function(data) {
		var value = asRawOrDie$1('Creating behaviour: ' + data.name, modeSchema, data)
		return createModes$1(
			choose$1(value.branchKey, value.branches),
			value.name,
			value.active,
			value.apis,
			value.extra,
			value.state
		)
	}
	var revoke = constant$1(undefined)

	var Swapping = create$5({
		fields: SwapSchema,
		name: 'swapping',
		apis: SwapApis
	})

	var Cell = function(initial) {
		var value = initial
		var get = function() {
			return value
		}
		var set = function(v) {
			value = v
		}
		return {
			get: get,
			set: set
		}
	}

	var getDocument = function() {
		return SugarElement.fromDom(document)
	}

	var focus$3 = function(element) {
		return element.dom.focus()
	}
	var blur$1 = function(element) {
		return element.dom.blur()
	}
	var hasFocus = function(element) {
		var root = getRootNode(element).dom
		return element.dom === root.activeElement
	}
	var active = function(root) {
		if (root === void 0) {
			root = getDocument()
		}
		return Optional.from(root.dom.activeElement).map(SugarElement.fromDom)
	}
	var search = function(element) {
		return active(getRootNode(element)).filter(function(e) {
			return element.dom.contains(e.dom)
		})
	}

	var global$5 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils')

	var global$4 = tinymce.util.Tools.resolve('tinymce.ThemeManager')

	var openLink = function(target) {
		var link = document.createElement('a')
		link.target = '_blank'
		link.href = target.href
		link.rel = 'noreferrer noopener'
		var nuEvt = document.createEvent('MouseEvents')
		nuEvt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
		document.body.appendChild(link)
		link.dispatchEvent(nuEvt)
		document.body.removeChild(link)
	}

	var DefaultStyleFormats = [
		{
			title: 'Headings',
			items: [
				{
					title: 'Heading 1',
					format: 'h1'
				},
				{
					title: 'Heading 2',
					format: 'h2'
				},
				{
					title: 'Heading 3',
					format: 'h3'
				},
				{
					title: 'Heading 4',
					format: 'h4'
				},
				{
					title: 'Heading 5',
					format: 'h5'
				},
				{
					title: 'Heading 6',
					format: 'h6'
				}
			]
		},
		{
			title: 'Inline',
			items: [
				{
					title: 'Bold',
					icon: 'bold',
					format: 'bold'
				},
				{
					title: 'Italic',
					icon: 'italic',
					format: 'italic'
				},
				{
					title: 'Underline',
					icon: 'underline',
					format: 'underline'
				},
				{
					title: 'Strikethrough',
					icon: 'strikethrough',
					format: 'strikethrough'
				},
				{
					title: 'Superscript',
					icon: 'superscript',
					format: 'superscript'
				},
				{
					title: 'Subscript',
					icon: 'subscript',
					format: 'subscript'
				},
				{
					title: 'Code',
					icon: 'code',
					format: 'code'
				}
			]
		},
		{
			title: 'Blocks',
			items: [
				{
					title: 'Paragraph',
					format: 'p'
				},
				{
					title: 'Blockquote',
					format: 'blockquote'
				},
				{
					title: 'Div',
					format: 'div'
				},
				{
					title: 'Pre',
					format: 'pre'
				}
			]
		},
		{
			title: 'Alignment',
			items: [
				{
					title: 'Left',
					icon: 'alignleft',
					format: 'alignleft'
				},
				{
					title: 'Center',
					icon: 'aligncenter',
					format: 'aligncenter'
				},
				{
					title: 'Right',
					icon: 'alignright',
					format: 'alignright'
				},
				{
					title: 'Justify',
					icon: 'alignjustify',
					format: 'alignjustify'
				}
			]
		}
	]

	var defaults = ['undo', 'bold', 'italic', 'link', 'image', 'bullist', 'styleselect']
	var isSkinDisabled = function(editor) {
		return editor.getParam('skin') === false
	}
	var readOnlyOnInit = function(_editor) {
		return false
	}
	var getToolbar = function(editor) {
		return editor.getParam('toolbar', defaults, 'array')
	}
	var getStyleFormats = function(editor) {
		return editor.getParam('style_formats', DefaultStyleFormats, 'array')
	}
	var getSkinUrl = function(editor) {
		return editor.getParam('skin_url')
	}

	var formatChanged = 'formatChanged'
	var orientationChanged = 'orientationChanged'
	var dropupDismissed = 'dropupDismissed'

	var fromHtml$1 = function(html, scope) {
		var doc = scope || document
		var div = doc.createElement('div')
		div.innerHTML = html
		return children(SugarElement.fromDom(div))
	}

	var get$9 = function(element) {
		return element.dom.innerHTML
	}
	var set$7 = function(element, content) {
		var owner = owner$2(element)
		var docDom = owner.dom
		var fragment = SugarElement.fromDom(docDom.createDocumentFragment())
		var contentElements = fromHtml$1(content, docDom)
		append$1(fragment, contentElements)
		empty(element)
		append$2(element, fragment)
	}
	var getOuter = function(element) {
		var container = SugarElement.fromTag('div')
		var clone = SugarElement.fromDom(element.dom.cloneNode(true))
		append$2(container, clone)
		return get$9(container)
	}

	var clone = function(original, isDeep) {
		return SugarElement.fromDom(original.dom.cloneNode(isDeep))
	}
	var shallow = function(original) {
		return clone(original, false)
	}

	var getHtml = function(element) {
		if (isShadowRoot(element)) {
			return '#shadow-root'
		} else {
			var clone = shallow(element)
			return getOuter(clone)
		}
	}

	var element = function(elem) {
		return getHtml(elem)
	}

	var chooseChannels = function(channels, message) {
		return message.universal
			? channels
			: filter$2(channels, function(ch) {
					return contains$1(message.channels, ch)
			  })
	}
	var events$a = function(receiveConfig) {
		return derive$3([
			run(receive$1(), function(component, message) {
				var channelMap = receiveConfig.channels
				var channels = keys(channelMap)
				var receivingData = message
				var targetChannels = chooseChannels(channels, receivingData)
				each$1(targetChannels, function(ch) {
					var channelInfo = channelMap[ch]
					var channelSchema = channelInfo.schema
					var data = asRawOrDie$1(
						'channel[' + ch + '] data\nReceiver: ' + element(component.element),
						channelSchema,
						receivingData.data
					)
					channelInfo.onReceive(component, data)
				})
			})
		])
	}

	var ActiveReceiving = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		events: events$a
	})

	var unknown = 'unknown'
	var EventConfiguration
	;(function(EventConfiguration) {
		EventConfiguration[(EventConfiguration['STOP'] = 0)] = 'STOP'
		EventConfiguration[(EventConfiguration['NORMAL'] = 1)] = 'NORMAL'
		EventConfiguration[(EventConfiguration['LOGGING'] = 2)] = 'LOGGING'
	})(EventConfiguration || (EventConfiguration = {}))
	var eventConfig = Cell({})
	var makeEventLogger = function(eventName, initialTarget) {
		var sequence = []
		var startTime = new Date().getTime()
		return {
			logEventCut: function(_name, target, purpose) {
				sequence.push({
					outcome: 'cut',
					target: target,
					purpose: purpose
				})
			},
			logEventStopped: function(_name, target, purpose) {
				sequence.push({
					outcome: 'stopped',
					target: target,
					purpose: purpose
				})
			},
			logNoParent: function(_name, target, purpose) {
				sequence.push({
					outcome: 'no-parent',
					target: target,
					purpose: purpose
				})
			},
			logEventNoHandlers: function(_name, target) {
				sequence.push({
					outcome: 'no-handlers-left',
					target: target
				})
			},
			logEventResponse: function(_name, target, purpose) {
				sequence.push({
					outcome: 'response',
					purpose: purpose,
					target: target
				})
			},
			write: function() {
				var finishTime = new Date().getTime()
				if (contains$1(['mousemove', 'mouseover', 'mouseout', systemInit()], eventName)) {
					return
				}
				console.log(eventName, {
					event: eventName,
					time: finishTime - startTime,
					target: initialTarget.dom,
					sequence: map$2(sequence, function(s) {
						if (!contains$1(['cut', 'stopped', 'response'], s.outcome)) {
							return s.outcome
						} else {
							return '{' + s.purpose + '} ' + s.outcome + ' at (' + element(s.target) + ')'
						}
					})
				})
			}
		}
	}
	var processEvent = function(eventName, initialTarget, f) {
		var status = get$c(eventConfig.get(), eventName)
			.orThunk(function() {
				var patterns = keys(eventConfig.get())
				return findMap(patterns, function(p) {
					return eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none()
				})
			})
			.getOr(EventConfiguration.NORMAL)
		switch (status) {
			case EventConfiguration.NORMAL:
				return f(noLogger())
			case EventConfiguration.LOGGING: {
				var logger = makeEventLogger(eventName, initialTarget)
				var output = f(logger)
				logger.write()
				return output
			}
			case EventConfiguration.STOP:
				return true
		}
	}
	var path = ['alloy/data/Fields', 'alloy/debugging/Debugging']
	var getTrace = function() {
		var err = new Error()
		if (err.stack !== undefined) {
			var lines = err.stack.split('\n')
			return find$2(lines, function(line) {
				return (
					line.indexOf('alloy') > 0 &&
					!exists(path, function(p) {
						return line.indexOf(p) > -1
					})
				)
			}).getOr(unknown)
		} else {
			return unknown
		}
	}
	var ignoreEvent = {
		logEventCut: noop,
		logEventStopped: noop,
		logNoParent: noop,
		logEventNoHandlers: noop,
		logEventResponse: noop,
		write: noop
	}
	var monitorEvent = function(eventName, initialTarget, f) {
		return processEvent(eventName, initialTarget, f)
	}
	var noLogger = constant$1(ignoreEvent)

	var menuFields = constant$1([required$1('menu'), required$1('selectedMenu')])
	var itemFields = constant$1([required$1('item'), required$1('selectedItem')])
	constant$1(objOf(itemFields().concat(menuFields())))
	var itemSchema$1 = constant$1(objOf(itemFields()))

	var _initSize = requiredObjOf('initSize', [required$1('numColumns'), required$1('numRows')])
	var itemMarkers = function() {
		return requiredOf('markers', itemSchema$1())
	}
	var tieredMenuMarkers = function() {
		return requiredObjOf('markers', [required$1('backgroundMenu')].concat(menuFields()).concat(itemFields()))
	}
	var markers = function(required) {
		return requiredObjOf('markers', map$2(required, required$1))
	}
	var onPresenceHandler = function(label, fieldName, presence) {
		getTrace()
		return field$2(
			fieldName,
			fieldName,
			presence,
			valueOf(function(f) {
				return Result.value(function() {
					var args = []
					for (var _i = 0; _i < arguments.length; _i++) {
						args[_i] = arguments[_i]
					}
					return f.apply(undefined, args)
				})
			})
		)
	}
	var onHandler = function(fieldName) {
		return onPresenceHandler('onHandler', fieldName, defaulted$1(noop))
	}
	var onKeyboardHandler = function(fieldName) {
		return onPresenceHandler('onKeyboardHandler', fieldName, defaulted$1(Optional.none))
	}
	var onStrictHandler = function(fieldName) {
		return onPresenceHandler('onHandler', fieldName, required$2())
	}
	var onStrictKeyboardHandler = function(fieldName) {
		return onPresenceHandler('onKeyboardHandler', fieldName, required$2())
	}
	var output = function(name, value) {
		return customField(name, constant$1(value))
	}
	var snapshot = function(name) {
		return customField(name, identity)
	}
	var initSize = constant$1(_initSize)

	var ReceivingSchema = [
		requiredOf(
			'channels',
			setOf(Result.value, objOfOnly([onStrictHandler('onReceive'), defaulted('schema', anyValue())]))
		)
	]

	var Receiving = create$5({
		fields: ReceivingSchema,
		name: 'receiving',
		active: ActiveReceiving
	})

	var SetupBehaviourCellState = function(initialState) {
		var init = function() {
			var cell = Cell(initialState)
			var get = function() {
				return cell.get()
			}
			var set = function(newState) {
				return cell.set(newState)
			}
			var clear = function() {
				return cell.set(initialState)
			}
			var readState = function() {
				return cell.get()
			}
			return {
				get: get,
				set: set,
				clear: clear,
				readState: readState
			}
		}
		return { init: init }
	}

	var updateAriaState = function(component, toggleConfig, toggleState) {
		var ariaInfo = toggleConfig.aria
		ariaInfo.update(component, ariaInfo, toggleState.get())
	}
	var updateClass = function(component, toggleConfig, toggleState) {
		toggleConfig.toggleClass.each(function(toggleClass) {
			if (toggleState.get()) {
				add$1(component.element, toggleClass)
			} else {
				remove$3(component.element, toggleClass)
			}
		})
	}
	var toggle = function(component, toggleConfig, toggleState) {
		set$6(component, toggleConfig, toggleState, !toggleState.get())
	}
	var on$1 = function(component, toggleConfig, toggleState) {
		toggleState.set(true)
		updateClass(component, toggleConfig, toggleState)
		updateAriaState(component, toggleConfig, toggleState)
	}
	var off = function(component, toggleConfig, toggleState) {
		toggleState.set(false)
		updateClass(component, toggleConfig, toggleState)
		updateAriaState(component, toggleConfig, toggleState)
	}
	var set$6 = function(component, toggleConfig, toggleState, state) {
		var action = state ? on$1 : off
		action(component, toggleConfig, toggleState)
	}
	var isOn = function(component, toggleConfig, toggleState) {
		return toggleState.get()
	}
	var onLoad$5 = function(component, toggleConfig, toggleState) {
		set$6(component, toggleConfig, toggleState, toggleConfig.selected)
	}

	var ToggleApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		onLoad: onLoad$5,
		toggle: toggle,
		isOn: isOn,
		on: on$1,
		off: off,
		set: set$6
	})

	var exhibit$5 = function() {
		return nu$3({})
	}
	var events$9 = function(toggleConfig, toggleState) {
		var execute = executeEvent(toggleConfig, toggleState, toggle)
		var load = loadEvent(toggleConfig, toggleState, onLoad$5)
		return derive$3(flatten([toggleConfig.toggleOnExecute ? [execute] : [], [load]]))
	}

	var ActiveToggle = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		exhibit: exhibit$5,
		events: events$9
	})

	var updatePressed = function(component, ariaInfo, status) {
		set$8(component.element, 'aria-pressed', status)
		if (ariaInfo.syncWithExpanded) {
			updateExpanded(component, ariaInfo, status)
		}
	}
	var updateSelected = function(component, ariaInfo, status) {
		set$8(component.element, 'aria-selected', status)
	}
	var updateChecked = function(component, ariaInfo, status) {
		set$8(component.element, 'aria-checked', status)
	}
	var updateExpanded = function(component, ariaInfo, status) {
		set$8(component.element, 'aria-expanded', status)
	}

	var ToggleSchema = [
		defaulted('selected', false),
		option('toggleClass'),
		defaulted('toggleOnExecute', true),
		defaultedOf(
			'aria',
			{ mode: 'none' },
			choose$1('mode', {
				pressed: [defaulted('syncWithExpanded', false), output('update', updatePressed)],
				checked: [output('update', updateChecked)],
				expanded: [output('update', updateExpanded)],
				selected: [output('update', updateSelected)],
				none: [output('update', noop)]
			})
		)
	]

	var Toggling = create$5({
		fields: ToggleSchema,
		name: 'toggling',
		active: ActiveToggle,
		apis: ToggleApis,
		state: SetupBehaviourCellState(false)
	})

	var format = function(command, update) {
		return Receiving.config({
			channels: wrap(formatChanged, {
				onReceive: function(button, data) {
					if (data.command === command) {
						update(button, data.state)
					}
				}
			})
		})
	}
	var orientation = function(onReceive) {
		return Receiving.config({ channels: wrap(orientationChanged, { onReceive: onReceive }) })
	}
	var receive = function(channel, onReceive) {
		return {
			key: channel,
			value: { onReceive: onReceive }
		}
	}

	var prefix$2 = 'tinymce-mobile'
	var resolve = function(p) {
		return prefix$2 + '-' + p
	}

	var pointerEvents = function() {
		var onClick = function(component, simulatedEvent) {
			simulatedEvent.stop()
			emitExecute(component)
		}
		return [run(click(), onClick), run(tap(), onClick), cutter(touchstart()), cutter(mousedown())]
	}
	var events$8 = function(optAction) {
		var executeHandler = function(action) {
			return runOnExecute(function(component, simulatedEvent) {
				action(component)
				simulatedEvent.stop()
			})
		}
		return derive$3(flatten([optAction.map(executeHandler).toArray(), pointerEvents()]))
	}

	var focus$2 = function(component, focusConfig) {
		if (!focusConfig.ignore) {
			focus$3(component.element)
			focusConfig.onFocus(component)
		}
	}
	var blur = function(component, focusConfig) {
		if (!focusConfig.ignore) {
			blur$1(component.element)
		}
	}
	var isFocused = function(component) {
		return hasFocus(component.element)
	}

	var FocusApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		focus: focus$2,
		blur: blur,
		isFocused: isFocused
	})

	var exhibit$4 = function(base, focusConfig) {
		var mod = focusConfig.ignore ? {} : { attributes: { tabindex: '-1' } }
		return nu$3(mod)
	}
	var events$7 = function(focusConfig) {
		return derive$3(
			[
				run(focus$4(), function(component, simulatedEvent) {
					focus$2(component, focusConfig)
					simulatedEvent.stop()
				})
			].concat(
				focusConfig.stopMousedown
					? [
							run(mousedown(), function(_, simulatedEvent) {
								simulatedEvent.event.prevent()
							})
					  ]
					: []
			)
		)
	}

	var ActiveFocus = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		exhibit: exhibit$4,
		events: events$7
	})

	var FocusSchema = [onHandler('onFocus'), defaulted('stopMousedown', false), defaulted('ignore', false)]

	var Focusing = create$5({
		fields: FocusSchema,
		name: 'focusing',
		active: ActiveFocus,
		apis: FocusApis
	})

	var isSupported = function(dom) {
		return dom.style !== undefined && isFunction(dom.style.getPropertyValue)
	}

	var internalSet = function(dom, property, value) {
		if (!isString(value)) {
			console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom)
			throw new Error('CSS value must be a string: ' + value)
		}
		if (isSupported(dom)) {
			dom.style.setProperty(property, value)
		}
	}
	var internalRemove = function(dom, property) {
		if (isSupported(dom)) {
			dom.style.removeProperty(property)
		}
	}
	var set$5 = function(element, property, value) {
		var dom = element.dom
		internalSet(dom, property, value)
	}
	var setAll = function(element, css) {
		var dom = element.dom
		each(css, function(v, k) {
			internalSet(dom, k, v)
		})
	}
	var get$8 = function(element, property) {
		var dom = element.dom
		var styles = window.getComputedStyle(dom)
		var r = styles.getPropertyValue(property)
		return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r
	}
	var getUnsafeProperty = function(dom, property) {
		return isSupported(dom) ? dom.style.getPropertyValue(property) : ''
	}
	var getRaw = function(element, property) {
		var dom = element.dom
		var raw = getUnsafeProperty(dom, property)
		return Optional.from(raw).filter(function(r) {
			return r.length > 0
		})
	}
	var remove$2 = function(element, property) {
		var dom = element.dom
		internalRemove(dom, property)
		if (is(getOpt(element, 'style').map(trim), '')) {
			remove$6(element, 'style')
		}
	}
	var reflow = function(e) {
		return e.dom.offsetWidth
	}

	var Dimension = function(name, getOffset) {
		var set = function(element, h) {
			if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
				throw new Error(name + '.set accepts only positive integer values. Value was ' + h)
			}
			var dom = element.dom
			if (isSupported(dom)) {
				dom.style[name] = h + 'px'
			}
		}
		var get = function(element) {
			var r = getOffset(element)
			if (r <= 0 || r === null) {
				var css = get$8(element, name)
				return parseFloat(css) || 0
			}
			return r
		}
		var getOuter = get
		var aggregate = function(element, properties) {
			return foldl(
				properties,
				function(acc, property) {
					var val = get$8(element, property)
					var value = val === undefined ? 0 : parseInt(val, 10)
					return isNaN(value) ? acc : acc + value
				},
				0
			)
		}
		var max = function(element, value, properties) {
			var cumulativeInclusions = aggregate(element, properties)
			var absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0
			return absoluteMax
		}
		return {
			set: set,
			get: get,
			getOuter: getOuter,
			aggregate: aggregate,
			max: max
		}
	}

	var api$3 = Dimension('height', function(element) {
		var dom = element.dom
		return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight
	})
	var get$7 = function(element) {
		return api$3.get(element)
	}

	var ancestors$1 = function(scope, predicate, isRoot) {
		return filter$2(parents(scope, isRoot), predicate)
	}
	var siblings$1 = function(scope, predicate) {
		return filter$2(siblings$2(scope), predicate)
	}

	var all = function(selector) {
		return all$2(selector)
	}
	var ancestors = function(scope, selector, isRoot) {
		return ancestors$1(
			scope,
			function(e) {
				return is$1(e, selector)
			},
			isRoot
		)
	}
	var siblings = function(scope, selector) {
		return siblings$1(scope, function(e) {
			return is$1(e, selector)
		})
	}
	var descendants = function(scope, selector) {
		return all$2(selector, scope)
	}

	function ClosestOrAncestor(is, ancestor, scope, a, isRoot) {
		if (is(scope, a)) {
			return Optional.some(scope)
		} else if (isFunction(isRoot) && isRoot(scope)) {
			return Optional.none()
		} else {
			return ancestor(scope, a, isRoot)
		}
	}

	var ancestor$1 = function(scope, predicate, isRoot) {
		var element = scope.dom
		var stop = isFunction(isRoot) ? isRoot : never
		while (element.parentNode) {
			element = element.parentNode
			var el = SugarElement.fromDom(element)
			if (predicate(el)) {
				return Optional.some(el)
			} else if (stop(el)) {
				break
			}
		}
		return Optional.none()
	}
	var closest$2 = function(scope, predicate, isRoot) {
		var is = function(s, test) {
			return test(s)
		}
		return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot)
	}
	var descendant$1 = function(scope, predicate) {
		var descend = function(node) {
			for (var i = 0; i < node.childNodes.length; i++) {
				var child_1 = SugarElement.fromDom(node.childNodes[i])
				if (predicate(child_1)) {
					return Optional.some(child_1)
				}
				var res = descend(node.childNodes[i])
				if (res.isSome()) {
					return res
				}
			}
			return Optional.none()
		}
		return descend(scope.dom)
	}

	var first$1 = function(selector) {
		return one(selector)
	}
	var ancestor = function(scope, selector, isRoot) {
		return ancestor$1(
			scope,
			function(e) {
				return is$1(e, selector)
			},
			isRoot
		)
	}
	var descendant = function(scope, selector) {
		return one(selector, scope)
	}
	var closest$1 = function(scope, selector, isRoot) {
		var is = function(element, selector) {
			return is$1(element, selector)
		}
		return ClosestOrAncestor(is, ancestor, scope, selector, isRoot)
	}

	var BACKSPACE = [8]
	var TAB = [9]
	var ENTER = [13]
	var ESCAPE = [27]
	var SPACE = [32]
	var LEFT = [37]
	var UP = [38]
	var RIGHT = [39]
	var DOWN = [40]

	var cyclePrev = function(values, index, predicate) {
		var before = reverse(values.slice(0, index))
		var after = reverse(values.slice(index + 1))
		return find$2(before.concat(after), predicate)
	}
	var tryPrev = function(values, index, predicate) {
		var before = reverse(values.slice(0, index))
		return find$2(before, predicate)
	}
	var cycleNext = function(values, index, predicate) {
		var before = values.slice(0, index)
		var after = values.slice(index + 1)
		return find$2(after.concat(before), predicate)
	}
	var tryNext = function(values, index, predicate) {
		var after = values.slice(index + 1)
		return find$2(after, predicate)
	}

	var inSet = function(keys) {
		return function(event) {
			var raw = event.raw
			return contains$1(keys, raw.which)
		}
	}
	var and = function(preds) {
		return function(event) {
			return forall(preds, function(pred) {
				return pred(event)
			})
		}
	}
	var isShift = function(event) {
		var raw = event.raw
		return raw.shiftKey === true
	}
	var isControl = function(event) {
		var raw = event.raw
		return raw.ctrlKey === true
	}
	var isNotShift = not(isShift)

	var rule = function(matches, action) {
		return {
			matches: matches,
			classification: action
		}
	}
	var choose = function(transitions, event) {
		var transition = find$2(transitions, function(t) {
			return t.matches(event)
		})
		return transition.map(function(t) {
			return t.classification
		})
	}

	var cycleBy = function(value, delta, min, max) {
		var r = value + delta
		if (r > max) {
			return min
		} else if (r < min) {
			return max
		} else {
			return r
		}
	}
	var clamp = function(value, min, max) {
		return Math.min(Math.max(value, min), max)
	}

	var dehighlightAllExcept = function(component, hConfig, hState, skip) {
		var highlighted = descendants(component.element, '.' + hConfig.highlightClass)
		each$1(highlighted, function(h) {
			if (
				!exists(skip, function(skipComp) {
					return skipComp.element === h
				})
			) {
				remove$3(h, hConfig.highlightClass)
				component
					.getSystem()
					.getByDom(h)
					.each(function(target) {
						hConfig.onDehighlight(component, target)
						emit(target, dehighlight$1())
					})
			}
		})
	}
	var dehighlightAll = function(component, hConfig, hState) {
		return dehighlightAllExcept(component, hConfig, hState, [])
	}
	var dehighlight = function(component, hConfig, hState, target) {
		if (isHighlighted(component, hConfig, hState, target)) {
			remove$3(target.element, hConfig.highlightClass)
			hConfig.onDehighlight(component, target)
			emit(target, dehighlight$1())
		}
	}
	var highlight = function(component, hConfig, hState, target) {
		dehighlightAllExcept(component, hConfig, hState, [target])
		if (!isHighlighted(component, hConfig, hState, target)) {
			add$1(target.element, hConfig.highlightClass)
			hConfig.onHighlight(component, target)
			emit(target, highlight$1())
		}
	}
	var highlightFirst = function(component, hConfig, hState) {
		getFirst(component, hConfig).each(function(firstComp) {
			highlight(component, hConfig, hState, firstComp)
		})
	}
	var highlightLast = function(component, hConfig, hState) {
		getLast(component, hConfig).each(function(lastComp) {
			highlight(component, hConfig, hState, lastComp)
		})
	}
	var highlightAt = function(component, hConfig, hState, index) {
		getByIndex(component, hConfig, hState, index).fold(
			function(err) {
				throw err
			},
			function(firstComp) {
				highlight(component, hConfig, hState, firstComp)
			}
		)
	}
	var highlightBy = function(component, hConfig, hState, predicate) {
		var candidates = getCandidates(component, hConfig)
		var targetComp = find$2(candidates, predicate)
		targetComp.each(function(c) {
			highlight(component, hConfig, hState, c)
		})
	}
	var isHighlighted = function(component, hConfig, hState, queryTarget) {
		return has(queryTarget.element, hConfig.highlightClass)
	}
	var getHighlighted = function(component, hConfig, _hState) {
		return descendant(component.element, '.' + hConfig.highlightClass).bind(function(e) {
			return component
				.getSystem()
				.getByDom(e)
				.toOptional()
		})
	}
	var getByIndex = function(component, hConfig, hState, index) {
		var items = descendants(component.element, '.' + hConfig.itemClass)
		return Optional.from(items[index]).fold(function() {
			return Result.error(new Error('No element found with index ' + index))
		}, component.getSystem().getByDom)
	}
	var getFirst = function(component, hConfig, _hState) {
		return descendant(component.element, '.' + hConfig.itemClass).bind(function(e) {
			return component
				.getSystem()
				.getByDom(e)
				.toOptional()
		})
	}
	var getLast = function(component, hConfig, _hState) {
		var items = descendants(component.element, '.' + hConfig.itemClass)
		var last = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none()
		return last.bind(function(c) {
			return component
				.getSystem()
				.getByDom(c)
				.toOptional()
		})
	}
	var getDelta = function(component, hConfig, hState, delta) {
		var items = descendants(component.element, '.' + hConfig.itemClass)
		var current = findIndex$1(items, function(item) {
			return has(item, hConfig.highlightClass)
		})
		return current.bind(function(selected) {
			var dest = cycleBy(selected, delta, 0, items.length - 1)
			return component
				.getSystem()
				.getByDom(items[dest])
				.toOptional()
		})
	}
	var getPrevious = function(component, hConfig, hState) {
		return getDelta(component, hConfig, hState, -1)
	}
	var getNext = function(component, hConfig, hState) {
		return getDelta(component, hConfig, hState, +1)
	}
	var getCandidates = function(component, hConfig, _hState) {
		var items = descendants(component.element, '.' + hConfig.itemClass)
		return cat(
			map$2(items, function(i) {
				return component
					.getSystem()
					.getByDom(i)
					.toOptional()
			})
		)
	}

	var HighlightApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		dehighlightAll: dehighlightAll,
		dehighlight: dehighlight,
		highlight: highlight,
		highlightFirst: highlightFirst,
		highlightLast: highlightLast,
		highlightAt: highlightAt,
		highlightBy: highlightBy,
		isHighlighted: isHighlighted,
		getHighlighted: getHighlighted,
		getFirst: getFirst,
		getLast: getLast,
		getPrevious: getPrevious,
		getNext: getNext,
		getCandidates: getCandidates
	})

	var HighlightSchema = [
		required$1('highlightClass'),
		required$1('itemClass'),
		onHandler('onHighlight'),
		onHandler('onDehighlight')
	]

	var Highlighting = create$5({
		fields: HighlightSchema,
		name: 'highlighting',
		apis: HighlightApis
	})

	var reportFocusShifting = function(component, prevFocus, newFocus) {
		var noChange = prevFocus.exists(function(p) {
			return newFocus.exists(function(n) {
				return eq(n, p)
			})
		})
		if (!noChange) {
			emitWith(component, focusShifted(), {
				prevFocus: prevFocus,
				newFocus: newFocus
			})
		}
	}
	var dom$2 = function() {
		var get = function(component) {
			return search(component.element)
		}
		var set = function(component, focusee) {
			var prevFocus = get(component)
			component.getSystem().triggerFocus(focusee, component.element)
			var newFocus = get(component)
			reportFocusShifting(component, prevFocus, newFocus)
		}
		return {
			get: get,
			set: set
		}
	}
	var highlights = function() {
		var get = function(component) {
			return Highlighting.getHighlighted(component).map(function(item) {
				return item.element
			})
		}
		var set = function(component, element) {
			var prevFocus = get(component)
			component
				.getSystem()
				.getByDom(element)
				.fold(noop, function(item) {
					Highlighting.highlight(component, item)
				})
			var newFocus = get(component)
			reportFocusShifting(component, prevFocus, newFocus)
		}
		return {
			get: get,
			set: set
		}
	}

	var FocusInsideModes
	;(function(FocusInsideModes) {
		FocusInsideModes['OnFocusMode'] = 'onFocus'
		FocusInsideModes['OnEnterOrSpaceMode'] = 'onEnterOrSpace'
		FocusInsideModes['OnApiMode'] = 'onApi'
	})(FocusInsideModes || (FocusInsideModes = {}))

	var typical = function(infoSchema, stateInit, getKeydownRules, getKeyupRules, optFocusIn) {
		var schema = function() {
			return infoSchema.concat([
				defaulted('focusManager', dom$2()),
				defaultedOf(
					'focusInside',
					'onFocus',
					valueOf(function(val) {
						return contains$1(['onFocus', 'onEnterOrSpace', 'onApi'], val)
							? Result.value(val)
							: Result.error('Invalid value for focusInside')
					})
				),
				output('handler', me),
				output('state', stateInit),
				output('sendFocusIn', optFocusIn)
			])
		}
		var processKey = function(component, simulatedEvent, getRules, keyingConfig, keyingState) {
			var rules = getRules(component, simulatedEvent, keyingConfig, keyingState)
			return choose(rules, simulatedEvent.event).bind(function(rule) {
				return rule(component, simulatedEvent, keyingConfig, keyingState)
			})
		}
		var toEvents = function(keyingConfig, keyingState) {
			var onFocusHandler =
				keyingConfig.focusInside !== FocusInsideModes.OnFocusMode
					? Optional.none()
					: optFocusIn(keyingConfig).map(function(focusIn) {
							return run(focus$4(), function(component, simulatedEvent) {
								focusIn(component, keyingConfig, keyingState)
								simulatedEvent.stop()
							})
					  })
			var tryGoInsideComponent = function(component, simulatedEvent) {
				var isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event)
				if (
					keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode &&
					isEnterOrSpace &&
					isSource(component, simulatedEvent)
				) {
					optFocusIn(keyingConfig).each(function(focusIn) {
						focusIn(component, keyingConfig, keyingState)
						simulatedEvent.stop()
					})
				}
			}
			var keyboardEvents = [
				run(keydown(), function(component, simulatedEvent) {
					processKey(component, simulatedEvent, getKeydownRules, keyingConfig, keyingState).fold(
						function() {
							tryGoInsideComponent(component, simulatedEvent)
						},
						function(_) {
							simulatedEvent.stop()
						}
					)
				}),
				run(keyup(), function(component, simulatedEvent) {
					processKey(component, simulatedEvent, getKeyupRules, keyingConfig, keyingState).each(function(_) {
						simulatedEvent.stop()
					})
				})
			]
			return derive$3(onFocusHandler.toArray().concat(keyboardEvents))
		}
		var me = {
			schema: schema,
			processKey: processKey,
			toEvents: toEvents
		}
		return me
	}

	var create$4 = function(cyclicField) {
		var schema = [
			option('onEscape'),
			option('onEnter'),
			defaulted('selector', '[data-alloy-tabstop="true"]:not(:disabled)'),
			defaulted('firstTabstop', 0),
			defaulted('useTabstopAt', always),
			option('visibilitySelector')
		].concat([cyclicField])
		var isVisible = function(tabbingConfig, element) {
			var target = tabbingConfig.visibilitySelector
				.bind(function(sel) {
					return closest$1(element, sel)
				})
				.getOr(element)
			return get$7(target) > 0
		}
		var findInitial = function(component, tabbingConfig) {
			var tabstops = descendants(component.element, tabbingConfig.selector)
			var visibles = filter$2(tabstops, function(elem) {
				return isVisible(tabbingConfig, elem)
			})
			return Optional.from(visibles[tabbingConfig.firstTabstop])
		}
		var findCurrent = function(component, tabbingConfig) {
			return tabbingConfig.focusManager.get(component).bind(function(elem) {
				return closest$1(elem, tabbingConfig.selector)
			})
		}
		var isTabstop = function(tabbingConfig, element) {
			return isVisible(tabbingConfig, element) && tabbingConfig.useTabstopAt(element)
		}
		var focusIn = function(component, tabbingConfig, _tabbingState) {
			findInitial(component, tabbingConfig).each(function(target) {
				tabbingConfig.focusManager.set(component, target)
			})
		}
		var goFromTabstop = function(component, tabstops, stopIndex, tabbingConfig, cycle) {
			return cycle(tabstops, stopIndex, function(elem) {
				return isTabstop(tabbingConfig, elem)
			}).fold(
				function() {
					return tabbingConfig.cyclic ? Optional.some(true) : Optional.none()
				},
				function(target) {
					tabbingConfig.focusManager.set(component, target)
					return Optional.some(true)
				}
			)
		}
		var go = function(component, _simulatedEvent, tabbingConfig, cycle) {
			var tabstops = descendants(component.element, tabbingConfig.selector)
			return findCurrent(component, tabbingConfig).bind(function(tabstop) {
				var optStopIndex = findIndex$1(tabstops, curry(eq, tabstop))
				return optStopIndex.bind(function(stopIndex) {
					return goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle)
				})
			})
		}
		var goBackwards = function(component, simulatedEvent, tabbingConfig) {
			var navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev
			return go(component, simulatedEvent, tabbingConfig, navigate)
		}
		var goForwards = function(component, simulatedEvent, tabbingConfig) {
			var navigate = tabbingConfig.cyclic ? cycleNext : tryNext
			return go(component, simulatedEvent, tabbingConfig, navigate)
		}
		var execute = function(component, simulatedEvent, tabbingConfig) {
			return tabbingConfig.onEnter.bind(function(f) {
				return f(component, simulatedEvent)
			})
		}
		var exit = function(component, simulatedEvent, tabbingConfig) {
			return tabbingConfig.onEscape.bind(function(f) {
				return f(component, simulatedEvent)
			})
		}
		var getKeydownRules = constant$1([
			rule(and([isShift, inSet(TAB)]), goBackwards),
			rule(inSet(TAB), goForwards),
			rule(inSet(ESCAPE), exit),
			rule(and([isNotShift, inSet(ENTER)]), execute)
		])
		var getKeyupRules = constant$1([])
		return typical(schema, NoState.init, getKeydownRules, getKeyupRules, function() {
			return Optional.some(focusIn)
		})
	}

	var AcyclicType = create$4(customField('cyclic', never))

	var CyclicType = create$4(customField('cyclic', always))

	var inside = function(target) {
		return (name$1(target) === 'input' && get$b(target, 'type') !== 'radio') || name$1(target) === 'textarea'
	}

	var doDefaultExecute = function(component, _simulatedEvent, focused) {
		dispatch(component, focused, execute$5())
		return Optional.some(true)
	}
	var defaultExecute = function(component, simulatedEvent, focused) {
		var isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event)
		return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused)
	}
	var stopEventForFirefox = function(_component, _simulatedEvent) {
		return Optional.some(true)
	}

	var schema$f = [
		defaulted('execute', defaultExecute),
		defaulted('useSpace', false),
		defaulted('useEnter', true),
		defaulted('useControlEnter', false),
		defaulted('useDown', false)
	]
	var execute$4 = function(component, simulatedEvent, executeConfig) {
		return executeConfig.execute(component, simulatedEvent, component.element)
	}
	var getKeydownRules$5 = function(component, _simulatedEvent, executeConfig, _executeState) {
		var spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : []
		var enterExec = executeConfig.useEnter ? ENTER : []
		var downExec = executeConfig.useDown ? DOWN : []
		var execKeys = spaceExec.concat(enterExec).concat(downExec)
		return [rule(inSet(execKeys), execute$4)].concat(
			executeConfig.useControlEnter ? [rule(and([isControl, inSet(ENTER)]), execute$4)] : []
		)
	}
	var getKeyupRules$5 = function(component, _simulatedEvent, executeConfig, _executeState) {
		return executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : []
	}
	var ExecutionType = typical(schema$f, NoState.init, getKeydownRules$5, getKeyupRules$5, function() {
		return Optional.none()
	})

	var singleton$1 = function(doRevoke) {
		var subject = Cell(Optional.none())
		var revoke = function() {
			return subject.get().each(doRevoke)
		}
		var clear = function() {
			revoke()
			subject.set(Optional.none())
		}
		var isSet = function() {
			return subject.get().isSome()
		}
		var get = function() {
			return subject.get()
		}
		var set = function(s) {
			revoke()
			subject.set(Optional.some(s))
		}
		return {
			clear: clear,
			isSet: isSet,
			get: get,
			set: set
		}
	}
	var destroyable = function() {
		return singleton$1(function(s) {
			return s.destroy()
		})
	}
	var api$2 = function() {
		var subject = destroyable()
		var run = function(f) {
			return subject.get().each(f)
		}
		return __assign(__assign({}, subject), { run: run })
	}
	var value = function() {
		var subject = singleton$1(noop)
		var on = function(f) {
			return subject.get().each(f)
		}
		return __assign(__assign({}, subject), { on: on })
	}

	var flatgrid$1 = function() {
		var dimensions = value()
		var setGridSize = function(numRows, numColumns) {
			dimensions.set({
				numRows: numRows,
				numColumns: numColumns
			})
		}
		var getNumRows = function() {
			return dimensions.get().map(function(d) {
				return d.numRows
			})
		}
		var getNumColumns = function() {
			return dimensions.get().map(function(d) {
				return d.numColumns
			})
		}
		return nu$2({
			readState: function() {
				return dimensions
					.get()
					.map(function(d) {
						return {
							numRows: String(d.numRows),
							numColumns: String(d.numColumns)
						}
					})
					.getOr({
						numRows: '?',
						numColumns: '?'
					})
			},
			setGridSize: setGridSize,
			getNumRows: getNumRows,
			getNumColumns: getNumColumns
		})
	}
	var init$5 = function(spec) {
		return spec.state(spec)
	}

	var KeyingState = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		flatgrid: flatgrid$1,
		init: init$5
	})

	var onDirection = function(isLtr, isRtl) {
		return function(element) {
			return getDirection(element) === 'rtl' ? isRtl : isLtr
		}
	}
	var getDirection = function(element) {
		return get$8(element, 'direction') === 'rtl' ? 'rtl' : 'ltr'
	}

	var useH = function(movement) {
		return function(component, simulatedEvent, config, state) {
			var move = movement(component.element)
			return use(move, component, simulatedEvent, config, state)
		}
	}
	var west = function(moveLeft, moveRight) {
		var movement = onDirection(moveLeft, moveRight)
		return useH(movement)
	}
	var east = function(moveLeft, moveRight) {
		var movement = onDirection(moveRight, moveLeft)
		return useH(movement)
	}
	var useV = function(move) {
		return function(component, simulatedEvent, config, state) {
			return use(move, component, simulatedEvent, config, state)
		}
	}
	var use = function(move, component, simulatedEvent, config, state) {
		var outcome = config.focusManager.get(component).bind(function(focused) {
			return move(component.element, focused, config, state)
		})
		return outcome.map(function(newFocus) {
			config.focusManager.set(component, newFocus)
			return true
		})
	}
	var north = useV
	var south = useV
	var move$1 = useV

	var isHidden = function(dom) {
		return dom.offsetWidth <= 0 && dom.offsetHeight <= 0
	}
	var isVisible = function(element) {
		return !isHidden(element.dom)
	}

	var locate = function(candidates, predicate) {
		return findIndex$1(candidates, predicate).map(function(index) {
			return {
				index: index,
				candidates: candidates
			}
		})
	}

	var locateVisible = function(container, current, selector) {
		var predicate = function(x) {
			return eq(x, current)
		}
		var candidates = descendants(container, selector)
		var visible = filter$2(candidates, isVisible)
		return locate(visible, predicate)
	}
	var findIndex = function(elements, target) {
		return findIndex$1(elements, function(elem) {
			return eq(target, elem)
		})
	}

	var withGrid = function(values, index, numCols, f) {
		var oldRow = Math.floor(index / numCols)
		var oldColumn = index % numCols
		return f(oldRow, oldColumn).bind(function(address) {
			var newIndex = address.row * numCols + address.column
			return newIndex >= 0 && newIndex < values.length ? Optional.some(values[newIndex]) : Optional.none()
		})
	}
	var cycleHorizontal$1 = function(values, index, numRows, numCols, delta) {
		return withGrid(values, index, numCols, function(oldRow, oldColumn) {
			var onLastRow = oldRow === numRows - 1
			var colsInRow = onLastRow ? values.length - oldRow * numCols : numCols
			var newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1)
			return Optional.some({
				row: oldRow,
				column: newColumn
			})
		})
	}
	var cycleVertical$1 = function(values, index, numRows, numCols, delta) {
		return withGrid(values, index, numCols, function(oldRow, oldColumn) {
			var newRow = cycleBy(oldRow, delta, 0, numRows - 1)
			var onLastRow = newRow === numRows - 1
			var colsInRow = onLastRow ? values.length - newRow * numCols : numCols
			var newCol = clamp(oldColumn, 0, colsInRow - 1)
			return Optional.some({
				row: newRow,
				column: newCol
			})
		})
	}
	var cycleRight$1 = function(values, index, numRows, numCols) {
		return cycleHorizontal$1(values, index, numRows, numCols, +1)
	}
	var cycleLeft$1 = function(values, index, numRows, numCols) {
		return cycleHorizontal$1(values, index, numRows, numCols, -1)
	}
	var cycleUp$1 = function(values, index, numRows, numCols) {
		return cycleVertical$1(values, index, numRows, numCols, -1)
	}
	var cycleDown$1 = function(values, index, numRows, numCols) {
		return cycleVertical$1(values, index, numRows, numCols, +1)
	}

	var schema$e = [
		required$1('selector'),
		defaulted('execute', defaultExecute),
		onKeyboardHandler('onEscape'),
		defaulted('captureTab', false),
		initSize()
	]
	var focusIn$3 = function(component, gridConfig, _gridState) {
		descendant(component.element, gridConfig.selector).each(function(first) {
			gridConfig.focusManager.set(component, first)
		})
	}
	var findCurrent$1 = function(component, gridConfig) {
		return gridConfig.focusManager.get(component).bind(function(elem) {
			return closest$1(elem, gridConfig.selector)
		})
	}
	var execute$3 = function(component, simulatedEvent, gridConfig, _gridState) {
		return findCurrent$1(component, gridConfig).bind(function(focused) {
			return gridConfig.execute(component, simulatedEvent, focused)
		})
	}
	var doMove$2 = function(cycle) {
		return function(element, focused, gridConfig, gridState) {
			return locateVisible(element, focused, gridConfig.selector).bind(function(identified) {
				return cycle(
					identified.candidates,
					identified.index,
					gridState.getNumRows().getOr(gridConfig.initSize.numRows),
					gridState.getNumColumns().getOr(gridConfig.initSize.numColumns)
				)
			})
		}
	}
	var handleTab = function(_component, _simulatedEvent, gridConfig) {
		return gridConfig.captureTab ? Optional.some(true) : Optional.none()
	}
	var doEscape$1 = function(component, simulatedEvent, gridConfig) {
		return gridConfig.onEscape(component, simulatedEvent)
	}
	var moveLeft$3 = doMove$2(cycleLeft$1)
	var moveRight$3 = doMove$2(cycleRight$1)
	var moveNorth$1 = doMove$2(cycleUp$1)
	var moveSouth$1 = doMove$2(cycleDown$1)
	var getKeydownRules$4 = constant$1([
		rule(inSet(LEFT), west(moveLeft$3, moveRight$3)),
		rule(inSet(RIGHT), east(moveLeft$3, moveRight$3)),
		rule(inSet(UP), north(moveNorth$1)),
		rule(inSet(DOWN), south(moveSouth$1)),
		rule(and([isShift, inSet(TAB)]), handleTab),
		rule(and([isNotShift, inSet(TAB)]), handleTab),
		rule(inSet(ESCAPE), doEscape$1),
		rule(inSet(SPACE.concat(ENTER)), execute$3)
	])
	var getKeyupRules$4 = constant$1([rule(inSet(SPACE), stopEventForFirefox)])
	var FlatgridType = typical(schema$e, flatgrid$1, getKeydownRules$4, getKeyupRules$4, function() {
		return Optional.some(focusIn$3)
	})

	var horizontal = function(container, selector, current, delta) {
		var isDisabledButton = function(candidate) {
			return name$1(candidate) === 'button' && get$b(candidate, 'disabled') === 'disabled'
		}
		var tryCycle = function(initial, index, candidates) {
			var newIndex = cycleBy(index, delta, 0, candidates.length - 1)
			if (newIndex === initial) {
				return Optional.none()
			} else {
				return isDisabledButton(candidates[newIndex])
					? tryCycle(initial, newIndex, candidates)
					: Optional.from(candidates[newIndex])
			}
		}
		return locateVisible(container, current, selector).bind(function(identified) {
			var index = identified.index
			var candidates = identified.candidates
			return tryCycle(index, index, candidates)
		})
	}

	var schema$d = [
		required$1('selector'),
		defaulted('getInitial', Optional.none),
		defaulted('execute', defaultExecute),
		onKeyboardHandler('onEscape'),
		defaulted('executeOnMove', false),
		defaulted('allowVertical', true)
	]
	var findCurrent = function(component, flowConfig) {
		return flowConfig.focusManager.get(component).bind(function(elem) {
			return closest$1(elem, flowConfig.selector)
		})
	}
	var execute$2 = function(component, simulatedEvent, flowConfig) {
		return findCurrent(component, flowConfig).bind(function(focused) {
			return flowConfig.execute(component, simulatedEvent, focused)
		})
	}
	var focusIn$2 = function(component, flowConfig, _state) {
		flowConfig
			.getInitial(component)
			.orThunk(function() {
				return descendant(component.element, flowConfig.selector)
			})
			.each(function(first) {
				flowConfig.focusManager.set(component, first)
			})
	}
	var moveLeft$2 = function(element, focused, info) {
		return horizontal(element, info.selector, focused, -1)
	}
	var moveRight$2 = function(element, focused, info) {
		return horizontal(element, info.selector, focused, +1)
	}
	var doMove$1 = function(movement) {
		return function(component, simulatedEvent, flowConfig, flowState) {
			return movement(component, simulatedEvent, flowConfig, flowState).bind(function() {
				return flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true)
			})
		}
	}
	var doEscape = function(component, simulatedEvent, flowConfig) {
		return flowConfig.onEscape(component, simulatedEvent)
	}
	var getKeydownRules$3 = function(_component, _se, flowConfig, _flowState) {
		var westMovers = LEFT.concat(flowConfig.allowVertical ? UP : [])
		var eastMovers = RIGHT.concat(flowConfig.allowVertical ? DOWN : [])
		return [
			rule(inSet(westMovers), doMove$1(west(moveLeft$2, moveRight$2))),
			rule(inSet(eastMovers), doMove$1(east(moveLeft$2, moveRight$2))),
			rule(inSet(ENTER), execute$2),
			rule(inSet(SPACE), execute$2),
			rule(inSet(ESCAPE), doEscape)
		]
	}
	var getKeyupRules$3 = constant$1([rule(inSet(SPACE), stopEventForFirefox)])
	var FlowType = typical(schema$d, NoState.init, getKeydownRules$3, getKeyupRules$3, function() {
		return Optional.some(focusIn$2)
	})

	var toCell = function(matrix, rowIndex, columnIndex) {
		return Optional.from(matrix[rowIndex]).bind(function(row) {
			return Optional.from(row[columnIndex]).map(function(cell) {
				return {
					rowIndex: rowIndex,
					columnIndex: columnIndex,
					cell: cell
				}
			})
		})
	}
	var cycleHorizontal = function(matrix, rowIndex, startCol, deltaCol) {
		var row = matrix[rowIndex]
		var colsInRow = row.length
		var newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1)
		return toCell(matrix, rowIndex, newColIndex)
	}
	var cycleVertical = function(matrix, colIndex, startRow, deltaRow) {
		var nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix.length - 1)
		var colsInNextRow = matrix[nextRowIndex].length
		var nextColIndex = clamp(colIndex, 0, colsInNextRow - 1)
		return toCell(matrix, nextRowIndex, nextColIndex)
	}
	var moveHorizontal = function(matrix, rowIndex, startCol, deltaCol) {
		var row = matrix[rowIndex]
		var colsInRow = row.length
		var newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1)
		return toCell(matrix, rowIndex, newColIndex)
	}
	var moveVertical = function(matrix, colIndex, startRow, deltaRow) {
		var nextRowIndex = clamp(startRow + deltaRow, 0, matrix.length - 1)
		var colsInNextRow = matrix[nextRowIndex].length
		var nextColIndex = clamp(colIndex, 0, colsInNextRow - 1)
		return toCell(matrix, nextRowIndex, nextColIndex)
	}
	var cycleRight = function(matrix, startRow, startCol) {
		return cycleHorizontal(matrix, startRow, startCol, +1)
	}
	var cycleLeft = function(matrix, startRow, startCol) {
		return cycleHorizontal(matrix, startRow, startCol, -1)
	}
	var cycleUp = function(matrix, startRow, startCol) {
		return cycleVertical(matrix, startCol, startRow, -1)
	}
	var cycleDown = function(matrix, startRow, startCol) {
		return cycleVertical(matrix, startCol, startRow, +1)
	}
	var moveLeft$1 = function(matrix, startRow, startCol) {
		return moveHorizontal(matrix, startRow, startCol, -1)
	}
	var moveRight$1 = function(matrix, startRow, startCol) {
		return moveHorizontal(matrix, startRow, startCol, +1)
	}
	var moveUp$1 = function(matrix, startRow, startCol) {
		return moveVertical(matrix, startCol, startRow, -1)
	}
	var moveDown$1 = function(matrix, startRow, startCol) {
		return moveVertical(matrix, startCol, startRow, +1)
	}

	var schema$c = [
		requiredObjOf('selectors', [required$1('row'), required$1('cell')]),
		defaulted('cycles', true),
		defaulted('previousSelector', Optional.none),
		defaulted('execute', defaultExecute)
	]
	var focusIn$1 = function(component, matrixConfig, _state) {
		var focused = matrixConfig.previousSelector(component).orThunk(function() {
			var selectors = matrixConfig.selectors
			return descendant(component.element, selectors.cell)
		})
		focused.each(function(cell) {
			matrixConfig.focusManager.set(component, cell)
		})
	}
	var execute$1 = function(component, simulatedEvent, matrixConfig) {
		return search(component.element).bind(function(focused) {
			return matrixConfig.execute(component, simulatedEvent, focused)
		})
	}
	var toMatrix = function(rows, matrixConfig) {
		return map$2(rows, function(row) {
			return descendants(row, matrixConfig.selectors.cell)
		})
	}
	var doMove = function(ifCycle, ifMove) {
		return function(element, focused, matrixConfig) {
			var move = matrixConfig.cycles ? ifCycle : ifMove
			return closest$1(focused, matrixConfig.selectors.row).bind(function(inRow) {
				var cellsInRow = descendants(inRow, matrixConfig.selectors.cell)
				return findIndex(cellsInRow, focused).bind(function(colIndex) {
					var allRows = descendants(element, matrixConfig.selectors.row)
					return findIndex(allRows, inRow).bind(function(rowIndex) {
						var matrix = toMatrix(allRows, matrixConfig)
						return move(matrix, rowIndex, colIndex).map(function(next) {
							return next.cell
						})
					})
				})
			})
		}
	}
	var moveLeft = doMove(cycleLeft, moveLeft$1)
	var moveRight = doMove(cycleRight, moveRight$1)
	var moveNorth = doMove(cycleUp, moveUp$1)
	var moveSouth = doMove(cycleDown, moveDown$1)
	var getKeydownRules$2 = constant$1([
		rule(inSet(LEFT), west(moveLeft, moveRight)),
		rule(inSet(RIGHT), east(moveLeft, moveRight)),
		rule(inSet(UP), north(moveNorth)),
		rule(inSet(DOWN), south(moveSouth)),
		rule(inSet(SPACE.concat(ENTER)), execute$1)
	])
	var getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)])
	var MatrixType = typical(schema$c, NoState.init, getKeydownRules$2, getKeyupRules$2, function() {
		return Optional.some(focusIn$1)
	})

	var schema$b = [required$1('selector'), defaulted('execute', defaultExecute), defaulted('moveOnTab', false)]
	var execute = function(component, simulatedEvent, menuConfig) {
		return menuConfig.focusManager.get(component).bind(function(focused) {
			return menuConfig.execute(component, simulatedEvent, focused)
		})
	}
	var focusIn = function(component, menuConfig, _state) {
		descendant(component.element, menuConfig.selector).each(function(first) {
			menuConfig.focusManager.set(component, first)
		})
	}
	var moveUp = function(element, focused, info) {
		return horizontal(element, info.selector, focused, -1)
	}
	var moveDown = function(element, focused, info) {
		return horizontal(element, info.selector, focused, +1)
	}
	var fireShiftTab = function(component, simulatedEvent, menuConfig, menuState) {
		return menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none()
	}
	var fireTab = function(component, simulatedEvent, menuConfig, menuState) {
		return menuConfig.moveOnTab
			? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState)
			: Optional.none()
	}
	var getKeydownRules$1 = constant$1([
		rule(inSet(UP), move$1(moveUp)),
		rule(inSet(DOWN), move$1(moveDown)),
		rule(and([isShift, inSet(TAB)]), fireShiftTab),
		rule(and([isNotShift, inSet(TAB)]), fireTab),
		rule(inSet(ENTER), execute),
		rule(inSet(SPACE), execute)
	])
	var getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)])
	var MenuType = typical(schema$b, NoState.init, getKeydownRules$1, getKeyupRules$1, function() {
		return Optional.some(focusIn)
	})

	var schema$a = [
		onKeyboardHandler('onSpace'),
		onKeyboardHandler('onEnter'),
		onKeyboardHandler('onShiftEnter'),
		onKeyboardHandler('onLeft'),
		onKeyboardHandler('onRight'),
		onKeyboardHandler('onTab'),
		onKeyboardHandler('onShiftTab'),
		onKeyboardHandler('onUp'),
		onKeyboardHandler('onDown'),
		onKeyboardHandler('onEscape'),
		defaulted('stopSpaceKeyup', false),
		option('focusIn')
	]
	var getKeydownRules = function(component, simulatedEvent, specialInfo) {
		return [
			rule(inSet(SPACE), specialInfo.onSpace),
			rule(and([isNotShift, inSet(ENTER)]), specialInfo.onEnter),
			rule(and([isShift, inSet(ENTER)]), specialInfo.onShiftEnter),
			rule(and([isShift, inSet(TAB)]), specialInfo.onShiftTab),
			rule(and([isNotShift, inSet(TAB)]), specialInfo.onTab),
			rule(inSet(UP), specialInfo.onUp),
			rule(inSet(DOWN), specialInfo.onDown),
			rule(inSet(LEFT), specialInfo.onLeft),
			rule(inSet(RIGHT), specialInfo.onRight),
			rule(inSet(SPACE), specialInfo.onSpace),
			rule(inSet(ESCAPE), specialInfo.onEscape)
		]
	}
	var getKeyupRules = function(component, simulatedEvent, specialInfo) {
		return specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : []
	}
	var SpecialType = typical(schema$a, NoState.init, getKeydownRules, getKeyupRules, function(specialInfo) {
		return specialInfo.focusIn
	})

	var acyclic = AcyclicType.schema()
	var cyclic = CyclicType.schema()
	var flow = FlowType.schema()
	var flatgrid = FlatgridType.schema()
	var matrix = MatrixType.schema()
	var execution = ExecutionType.schema()
	var menu = MenuType.schema()
	var special = SpecialType.schema()

	var KeyboardBranches = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		acyclic: acyclic,
		cyclic: cyclic,
		flow: flow,
		flatgrid: flatgrid,
		matrix: matrix,
		execution: execution,
		menu: menu,
		special: special
	})

	var isFlatgridState = function(keyState) {
		return hasNonNullableKey(keyState, 'setGridSize')
	}
	var Keying = createModes({
		branchKey: 'mode',
		branches: KeyboardBranches,
		name: 'keying',
		active: {
			events: function(keyingConfig, keyingState) {
				var handler = keyingConfig.handler
				return handler.toEvents(keyingConfig, keyingState)
			}
		},
		apis: {
			focusIn: function(component, keyConfig, keyState) {
				keyConfig.sendFocusIn(keyConfig).fold(
					function() {
						component.getSystem().triggerFocus(component.element, component.element)
					},
					function(sendFocusIn) {
						sendFocusIn(component, keyConfig, keyState)
					}
				)
			},
			setGridSize: function(component, keyConfig, keyState, numRows, numColumns) {
				if (!isFlatgridState(keyState)) {
					console.error('Layout does not support setGridSize')
				} else {
					keyState.setGridSize(numRows, numColumns)
				}
			}
		},
		state: KeyingState
	})

	var field$1 = function(name, forbidden) {
		return defaultedObjOf(
			name,
			{},
			map$2(forbidden, function(f) {
				return forbid(f.name(), 'Cannot configure ' + f.name() + ' for ' + name)
			}).concat([customField('dump', identity)])
		)
	}
	var get$6 = function(data) {
		return data.dump
	}
	var augment = function(data, original) {
		return __assign(__assign({}, derive$2(original)), data.dump)
	}
	var SketchBehaviours = {
		field: field$1,
		augment: augment,
		get: get$6
	}

	var _placeholder = 'placeholder'
	var adt$5 = Adt.generate([
		{
			single: ['required', 'valueThunk']
		},
		{
			multiple: ['required', 'valueThunks']
		}
	])
	var isSubstituted = function(spec) {
		return has$2(spec, 'uiType')
	}
	var subPlaceholder = function(owner, detail, compSpec, placeholders) {
		if (
			owner.exists(function(o) {
				return o !== compSpec.owner
			})
		) {
			return adt$5.single(true, constant$1(compSpec))
		}
		return get$c(placeholders, compSpec.name).fold(
			function() {
				throw new Error(
					'Unknown placeholder component: ' +
						compSpec.name +
						'\nKnown: [' +
						keys(placeholders) +
						']\nNamespace: ' +
						owner.getOr('none') +
						'\nSpec: ' +
						JSON.stringify(compSpec, null, 2)
				)
			},
			function(newSpec) {
				return newSpec.replace()
			}
		)
	}
	var scan = function(owner, detail, compSpec, placeholders) {
		if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
			return subPlaceholder(owner, detail, compSpec, placeholders)
		} else {
			return adt$5.single(false, constant$1(compSpec))
		}
	}
	var substitute = function(owner, detail, compSpec, placeholders) {
		var base = scan(owner, detail, compSpec, placeholders)
		return base.fold(
			function(req, valueThunk) {
				var value = isSubstituted(compSpec)
					? valueThunk(detail, compSpec.config, compSpec.validated)
					: valueThunk(detail)
				var childSpecs = get$c(value, 'components').getOr([])
				var substituted = bind$3(childSpecs, function(c) {
					return substitute(owner, detail, c, placeholders)
				})
				return [__assign(__assign({}, value), { components: substituted })]
			},
			function(req, valuesThunk) {
				if (isSubstituted(compSpec)) {
					var values = valuesThunk(detail, compSpec.config, compSpec.validated)
					var preprocessor = compSpec.validated.preprocess.getOr(identity)
					return preprocessor(values)
				} else {
					return valuesThunk(detail)
				}
			}
		)
	}
	var substituteAll = function(owner, detail, components, placeholders) {
		return bind$3(components, function(c) {
			return substitute(owner, detail, c, placeholders)
		})
	}
	var oneReplace = function(label, replacements) {
		var called = false
		var used = function() {
			return called
		}
		var replace = function() {
			if (called) {
				throw new Error('Trying to use the same placeholder more than once: ' + label)
			}
			called = true
			return replacements
		}
		var required = function() {
			return replacements.fold(
				function(req, _) {
					return req
				},
				function(req, _) {
					return req
				}
			)
		}
		return {
			name: constant$1(label),
			required: required,
			used: used,
			replace: replace
		}
	}
	var substitutePlaces = function(owner, detail, components, placeholders) {
		var ps = map$1(placeholders, function(ph, name) {
			return oneReplace(name, ph)
		})
		var outcome = substituteAll(owner, detail, components, ps)
		each(ps, function(p) {
			if (p.used() === false && p.required()) {
				throw new Error(
					'Placeholder: ' +
						p.name() +
						' was not found in components list\nNamespace: ' +
						owner.getOr('none') +
						'\nComponents: ' +
						JSON.stringify(detail.components, null, 2)
				)
			}
		})
		return outcome
	}
	var single$2 = adt$5.single
	var multiple = adt$5.multiple
	var placeholder = constant$1(_placeholder)

	var unique = 0
	var generate$4 = function(prefix) {
		var date = new Date()
		var time = date.getTime()
		var random = Math.floor(Math.random() * 1000000000)
		unique++
		return prefix + '_' + random + unique + String(time)
	}

	var adt$4 = Adt.generate([
		{ required: ['data'] },
		{ external: ['data'] },
		{ optional: ['data'] },
		{ group: ['data'] }
	])
	var fFactory = defaulted('factory', { sketch: identity })
	var fSchema = defaulted('schema', [])
	var fName = required$1('name')
	var fPname = field$2(
		'pname',
		'pname',
		defaultedThunk(function(typeSpec) {
			return '<alloy.' + generate$4(typeSpec.name) + '>'
		}),
		anyValue()
	)
	var fGroupSchema = customField('schema', function() {
		return [option('preprocess')]
	})
	var fDefaults = defaulted('defaults', constant$1({}))
	var fOverrides = defaulted('overrides', constant$1({}))
	var requiredSpec = objOf([fFactory, fSchema, fName, fPname, fDefaults, fOverrides])
	var externalSpec = objOf([fFactory, fSchema, fName, fDefaults, fOverrides])
	var optionalSpec = objOf([fFactory, fSchema, fName, fPname, fDefaults, fOverrides])
	var groupSpec = objOf([fFactory, fGroupSchema, fName, required$1('unit'), fPname, fDefaults, fOverrides])
	var asNamedPart = function(part) {
		return part.fold(Optional.some, Optional.none, Optional.some, Optional.some)
	}
	var name = function(part) {
		var get = function(data) {
			return data.name
		}
		return part.fold(get, get, get, get)
	}
	var convert$1 = function(adtConstructor, partSchema) {
		return function(spec) {
			var data = asRawOrDie$1('Converting part type', partSchema, spec)
			return adtConstructor(data)
		}
	}
	var required = convert$1(adt$4.required, requiredSpec)
	convert$1(adt$4.external, externalSpec)
	var optional = convert$1(adt$4.optional, optionalSpec)
	var group = convert$1(adt$4.group, groupSpec)
	var original = constant$1('entirety')

	var combine$2 = function(detail, data, partSpec, partValidated) {
		return deepMerge(
			data.defaults(detail, partSpec, partValidated),
			partSpec,
			{ uid: detail.partUids[data.name] },
			data.overrides(detail, partSpec, partValidated)
		)
	}
	var subs = function(owner, detail, parts) {
		var internals = {}
		var externals = {}
		each$1(parts, function(part) {
			part.fold(
				function(data) {
					internals[data.pname] = single$2(true, function(detail, partSpec, partValidated) {
						return data.factory.sketch(combine$2(detail, data, partSpec, partValidated))
					})
				},
				function(data) {
					var partSpec = detail.parts[data.name]
					externals[data.name] = constant$1(
						data.factory.sketch(combine$2(detail, data, partSpec[original()]), partSpec)
					)
				},
				function(data) {
					internals[data.pname] = single$2(false, function(detail, partSpec, partValidated) {
						return data.factory.sketch(combine$2(detail, data, partSpec, partValidated))
					})
				},
				function(data) {
					internals[data.pname] = multiple(true, function(detail, _partSpec, _partValidated) {
						var units = detail[data.name]
						return map$2(units, function(u) {
							return data.factory.sketch(
								deepMerge(data.defaults(detail, u, _partValidated), u, data.overrides(detail, u))
							)
						})
					})
				}
			)
		})
		return {
			internals: constant$1(internals),
			externals: constant$1(externals)
		}
	}

	var generate$3 = function(owner, parts) {
		var r = {}
		each$1(parts, function(part) {
			asNamedPart(part).each(function(np) {
				var g = doGenerateOne(owner, np.pname)
				r[np.name] = function(config) {
					var validated = asRawOrDie$1('Part: ' + np.name + ' in ' + owner, objOf(np.schema), config)
					return __assign(__assign({}, g), {
						config: config,
						validated: validated
					})
				}
			})
		})
		return r
	}
	var doGenerateOne = function(owner, pname) {
		return {
			uiType: placeholder(),
			owner: owner,
			name: pname
		}
	}
	var generateOne = function(owner, pname, config) {
		return {
			uiType: placeholder(),
			owner: owner,
			name: pname,
			config: config,
			validated: {}
		}
	}
	var schemas = function(parts) {
		return bind$3(parts, function(part) {
			return part
				.fold(Optional.none, Optional.some, Optional.none, Optional.none)
				.map(function(data) {
					return requiredObjOf(data.name, data.schema.concat([snapshot(original())]))
				})
				.toArray()
		})
	}
	var names = function(parts) {
		return map$2(parts, name)
	}
	var substitutes = function(owner, detail, parts) {
		return subs(owner, detail, parts)
	}
	var components = function(owner, detail, internals) {
		return substitutePlaces(Optional.some(owner), detail, detail.components, internals)
	}
	var getPart = function(component, detail, partKey) {
		var uid = detail.partUids[partKey]
		return component
			.getSystem()
			.getByUid(uid)
			.toOptional()
	}
	var getPartOrDie = function(component, detail, partKey) {
		return getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey)
	}
	var getAllParts = function(component, detail) {
		var system = component.getSystem()
		return map$1(detail.partUids, function(pUid, _k) {
			return constant$1(system.getByUid(pUid))
		})
	}
	var defaultUids = function(baseUid, partTypes) {
		var partNames = names(partTypes)
		return wrapAll(
			map$2(partNames, function(pn) {
				return {
					key: pn,
					value: baseUid + '-' + pn
				}
			})
		)
	}
	var defaultUidsSchema = function(partTypes) {
		return field$2(
			'partUids',
			'partUids',
			mergeWithThunk(function(spec) {
				return defaultUids(spec.uid, partTypes)
			}),
			anyValue()
		)
	}

	var premadeTag = generate$4('alloy-premade')
	var premade$1 = function(comp) {
		return wrap(premadeTag, comp)
	}
	var getPremade = function(spec) {
		return get$c(spec, premadeTag)
	}
	var makeApi = function(f) {
		return markAsSketchApi(function(component) {
			var rest = []
			for (var _i = 1; _i < arguments.length; _i++) {
				rest[_i - 1] = arguments[_i]
			}
			return f.apply(void 0, __spreadArray([component.getApis(), component], rest, false))
		}, f)
	}

	var prefix$1 = constant$1('alloy-id-')
	var idAttr$1 = constant$1('data-alloy-id')

	var prefix = prefix$1()
	var idAttr = idAttr$1()
	var write = function(label, elem) {
		var id = generate$4(prefix + label)
		writeOnly(elem, id)
		return id
	}
	var writeOnly = function(elem, uid) {
		Object.defineProperty(elem.dom, idAttr, {
			value: uid,
			writable: true
		})
	}
	var read = function(elem) {
		var id = isElement(elem) ? elem.dom[idAttr] : null
		return Optional.from(id)
	}
	var generate$2 = function(prefix) {
		return generate$4(prefix)
	}

	var base = function(partSchemas, partUidsSchemas) {
		var ps = partSchemas.length > 0 ? [requiredObjOf('parts', partSchemas)] : []
		return ps
			.concat([
				required$1('uid'),
				defaulted('dom', {}),
				defaulted('components', []),
				snapshot('originalSpec'),
				defaulted('debug.sketcher', {})
			])
			.concat(partUidsSchemas)
	}
	var asRawOrDie = function(label, schema, spec, partSchemas, partUidsSchemas) {
		var baseS = base(partSchemas, partUidsSchemas)
		return asRawOrDie$1(label + ' [SpecSchema]', objOfOnly(baseS.concat(schema)), spec)
	}

	var single$1 = function(owner, schema, factory, spec) {
		var specWithUid = supplyUid(spec)
		var detail = asRawOrDie(owner, schema, specWithUid, [], [])
		return factory(detail, specWithUid)
	}
	var composite$1 = function(owner, schema, partTypes, factory, spec) {
		var specWithUid = supplyUid(spec)
		var partSchemas = schemas(partTypes)
		var partUidsSchema = defaultUidsSchema(partTypes)
		var detail = asRawOrDie(owner, schema, specWithUid, partSchemas, [partUidsSchema])
		var subs = substitutes(owner, detail, partTypes)
		var components$1 = components(owner, detail, subs.internals())
		return factory(detail, components$1, specWithUid, subs.externals())
	}
	var hasUid = function(spec) {
		return has$2(spec, 'uid')
	}
	var supplyUid = function(spec) {
		return hasUid(spec) ? spec : __assign(__assign({}, spec), { uid: generate$2('uid') })
	}

	var isSketchSpec$1 = function(spec) {
		return spec.uid !== undefined
	}
	var singleSchema = objOfOnly([
		required$1('name'),
		required$1('factory'),
		required$1('configFields'),
		defaulted('apis', {}),
		defaulted('extraApis', {})
	])
	var compositeSchema = objOfOnly([
		required$1('name'),
		required$1('factory'),
		required$1('configFields'),
		required$1('partFields'),
		defaulted('apis', {}),
		defaulted('extraApis', {})
	])
	var single = function(rawConfig) {
		var config = asRawOrDie$1('Sketcher for ' + rawConfig.name, singleSchema, rawConfig)
		var sketch = function(spec) {
			return single$1(config.name, config.configFields, config.factory, spec)
		}
		var apis = map$1(config.apis, makeApi)
		var extraApis = map$1(config.extraApis, function(f, k) {
			return markAsExtraApi(f, k)
		})
		return __assign(
			__assign(
				{
					name: config.name,
					configFields: config.configFields,
					sketch: sketch
				},
				apis
			),
			extraApis
		)
	}
	var composite = function(rawConfig) {
		var config = asRawOrDie$1('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig)
		var sketch = function(spec) {
			return composite$1(config.name, config.configFields, config.partFields, config.factory, spec)
		}
		var parts = generate$3(config.name, config.partFields)
		var apis = map$1(config.apis, makeApi)
		var extraApis = map$1(config.extraApis, function(f, k) {
			return markAsExtraApi(f, k)
		})
		return __assign(
			__assign(
				{
					name: config.name,
					partFields: config.partFields,
					configFields: config.configFields,
					sketch: sketch,
					parts: parts
				},
				apis
			),
			extraApis
		)
	}

	var factory$5 = function(detail) {
		var events = events$8(detail.action)
		var tag = detail.dom.tag
		var lookupAttr = function(attr) {
			return get$c(detail.dom, 'attributes').bind(function(attrs) {
				return get$c(attrs, attr)
			})
		}
		var getModAttributes = function() {
			if (tag === 'button') {
				var type = lookupAttr('type').getOr('button')
				var roleAttrs = lookupAttr('role')
					.map(function(role) {
						return { role: role }
					})
					.getOr({})
				return __assign({ type: type }, roleAttrs)
			} else {
				var role = lookupAttr('role').getOr('button')
				return { role: role }
			}
		}
		return {
			uid: detail.uid,
			dom: detail.dom,
			components: detail.components,
			events: events,
			behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
				Focusing.config({}),
				Keying.config({
					mode: 'execution',
					useSpace: true,
					useEnter: true
				})
			]),
			domModification: { attributes: getModAttributes() },
			eventOrder: detail.eventOrder
		}
	}
	var Button = single({
		name: 'Button',
		factory: factory$5,
		configFields: [
			defaulted('uid', undefined),
			required$1('dom'),
			defaulted('components', []),
			SketchBehaviours.field('buttonBehaviours', [Focusing, Keying]),
			option('action'),
			option('role'),
			defaulted('eventOrder', {})
		]
	})

	var exhibit$3 = function() {
		return nu$3({
			styles: {
				'-webkit-user-select': 'none',
				'user-select': 'none',
				'-ms-user-select': 'none',
				'-moz-user-select': '-moz-none'
			},
			attributes: { unselectable: 'on' }
		})
	}
	var events$6 = function() {
		return derive$3([abort(selectstart(), always)])
	}

	var ActiveUnselecting = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		events: events$6,
		exhibit: exhibit$3
	})

	var Unselecting = create$5({
		fields: [],
		name: 'unselecting',
		active: ActiveUnselecting
	})

	var getAttrs$1 = function(elem) {
		var attributes = elem.dom.attributes !== undefined ? elem.dom.attributes : []
		return foldl(
			attributes,
			function(b, attr) {
				var _a
				if (attr.name === 'class') {
					return b
				} else {
					return __assign(__assign({}, b), ((_a = {}), (_a[attr.name] = attr.value), _a))
				}
			},
			{}
		)
	}
	var getClasses = function(elem) {
		return Array.prototype.slice.call(elem.dom.classList, 0)
	}
	var fromHtml = function(html) {
		var elem = SugarElement.fromHtml(html)
		var children$1 = children(elem)
		var attrs = getAttrs$1(elem)
		var classes = getClasses(elem)
		var contents = children$1.length === 0 ? {} : { innerHtml: get$9(elem) }
		return __assign(
			{
				tag: name$1(elem),
				classes: classes,
				attributes: attrs
			},
			contents
		)
	}

	var dom$1 = function(rawHtml) {
		var html = supplant(rawHtml, { prefix: prefix$2 })
		return fromHtml(html)
	}
	var spec = function(rawHtml) {
		return { dom: dom$1(rawHtml) }
	}

	var forToolbarCommand = function(editor, command) {
		return forToolbar(
			command,
			function() {
				editor.execCommand(command)
			},
			{},
			editor
		)
	}
	var getToggleBehaviours = function(command) {
		return derive$2([
			Toggling.config({
				toggleClass: resolve('toolbar-button-selected'),
				toggleOnExecute: false,
				aria: { mode: 'pressed' }
			}),
			format(command, function(button, status) {
				var toggle = status ? Toggling.on : Toggling.off
				toggle(button)
			})
		])
	}
	var forToolbarStateCommand = function(editor, command) {
		var extraBehaviours = getToggleBehaviours(command)
		return forToolbar(
			command,
			function() {
				editor.execCommand(command)
			},
			extraBehaviours,
			editor
		)
	}
	var forToolbarStateAction = function(editor, clazz, command, action) {
		var extraBehaviours = getToggleBehaviours(command)
		return forToolbar(clazz, action, extraBehaviours, editor)
	}
	var getToolbarIconButton = function(clazz, editor) {
		var icons = editor.ui.registry.getAll().icons
		var optOxideIcon = Optional.from(icons[clazz])
		return optOxideIcon.fold(
			function() {
				return dom$1(
					'<span class="${prefix}-toolbar-button ${prefix}-toolbar-group-item ${prefix}-icon-' +
						clazz +
						' ${prefix}-icon"></span>'
				)
			},
			function(icon) {
				return dom$1('<span class="${prefix}-toolbar-button ${prefix}-toolbar-group-item">' + icon + '</span>')
			}
		)
	}
	var forToolbar = function(clazz, action, extraBehaviours, editor) {
		return Button.sketch({
			dom: getToolbarIconButton(clazz, editor),
			action: action,
			buttonBehaviours: deepMerge(derive$2([Unselecting.config({})]), extraBehaviours)
		})
	}

	var labelPart = optional({
		schema: [required$1('dom')],
		name: 'label'
	})
	var edgePart = function(name) {
		return optional({
			name: '' + name + '-edge',
			overrides: function(detail) {
				var action = detail.model.manager.edgeActions[name]
				return action.fold(
					function() {
						return {}
					},
					function(a) {
						return {
							events: derive$3([
								runActionExtra(
									touchstart(),
									function(comp, se, d) {
										return a(comp, d)
									},
									[detail]
								),
								runActionExtra(
									mousedown(),
									function(comp, se, d) {
										return a(comp, d)
									},
									[detail]
								),
								runActionExtra(
									mousemove(),
									function(comp, se, det) {
										if (det.mouseIsDown.get()) {
											a(comp, det)
										}
									},
									[detail]
								)
							])
						}
					}
				)
			}
		})
	}
	var tlEdgePart = edgePart('top-left')
	var tedgePart = edgePart('top')
	var trEdgePart = edgePart('top-right')
	var redgePart = edgePart('right')
	var brEdgePart = edgePart('bottom-right')
	var bedgePart = edgePart('bottom')
	var blEdgePart = edgePart('bottom-left')
	var ledgePart = edgePart('left')
	var thumbPart = required({
		name: 'thumb',
		defaults: constant$1({ dom: { styles: { position: 'absolute' } } }),
		overrides: function(detail) {
			return {
				events: derive$3([
					redirectToPart(touchstart(), detail, 'spectrum'),
					redirectToPart(touchmove(), detail, 'spectrum'),
					redirectToPart(touchend(), detail, 'spectrum'),
					redirectToPart(mousedown(), detail, 'spectrum'),
					redirectToPart(mousemove(), detail, 'spectrum'),
					redirectToPart(mouseup(), detail, 'spectrum')
				])
			}
		}
	})
	var spectrumPart = required({
		schema: [
			customField('mouseIsDown', function() {
				return Cell(false)
			})
		],
		name: 'spectrum',
		overrides: function(detail) {
			var modelDetail = detail.model
			var model = modelDetail.manager
			var setValueFrom = function(component, simulatedEvent) {
				return model.getValueFromEvent(simulatedEvent).map(function(value) {
					return model.setValueFrom(component, detail, value)
				})
			}
			return {
				behaviours: derive$2([
					Keying.config({
						mode: 'special',
						onLeft: function(spectrum) {
							return model.onLeft(spectrum, detail)
						},
						onRight: function(spectrum) {
							return model.onRight(spectrum, detail)
						},
						onUp: function(spectrum) {
							return model.onUp(spectrum, detail)
						},
						onDown: function(spectrum) {
							return model.onDown(spectrum, detail)
						}
					}),
					Focusing.config({})
				]),
				events: derive$3([
					run(touchstart(), setValueFrom),
					run(touchmove(), setValueFrom),
					run(mousedown(), setValueFrom),
					run(mousemove(), function(spectrum, se) {
						if (detail.mouseIsDown.get()) {
							setValueFrom(spectrum, se)
						}
					})
				])
			}
		}
	})
	var SliderParts = [
		labelPart,
		ledgePart,
		redgePart,
		tedgePart,
		bedgePart,
		tlEdgePart,
		trEdgePart,
		blEdgePart,
		brEdgePart,
		thumbPart,
		spectrumPart
	]

	var onLoad$4 = function(component, repConfig, repState) {
		repConfig.store.manager.onLoad(component, repConfig, repState)
	}
	var onUnload$2 = function(component, repConfig, repState) {
		repConfig.store.manager.onUnload(component, repConfig, repState)
	}
	var setValue$3 = function(component, repConfig, repState, data) {
		repConfig.store.manager.setValue(component, repConfig, repState, data)
	}
	var getValue$4 = function(component, repConfig, repState) {
		return repConfig.store.manager.getValue(component, repConfig, repState)
	}
	var getState$1 = function(component, repConfig, repState) {
		return repState
	}

	var RepresentApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		onLoad: onLoad$4,
		onUnload: onUnload$2,
		setValue: setValue$3,
		getValue: getValue$4,
		getState: getState$1
	})

	var events$5 = function(repConfig, repState) {
		var es = repConfig.resetOnDom
			? [
					runOnAttached(function(comp, _se) {
						onLoad$4(comp, repConfig, repState)
					}),
					runOnDetached(function(comp, _se) {
						onUnload$2(comp, repConfig, repState)
					})
			  ]
			: [loadEvent(repConfig, repState, onLoad$4)]
		return derive$3(es)
	}

	var ActiveRepresenting = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		events: events$5
	})

	var memory = function() {
		var data = Cell(null)
		var readState = function() {
			return {
				mode: 'memory',
				value: data.get()
			}
		}
		var isNotSet = function() {
			return data.get() === null
		}
		var clear = function() {
			data.set(null)
		}
		return nu$2({
			set: data.set,
			get: data.get,
			isNotSet: isNotSet,
			clear: clear,
			readState: readState
		})
	}
	var manual = function() {
		var readState = noop
		return nu$2({ readState: readState })
	}
	var dataset = function() {
		var dataByValue = Cell({})
		var dataByText = Cell({})
		var readState = function() {
			return {
				mode: 'dataset',
				dataByValue: dataByValue.get(),
				dataByText: dataByText.get()
			}
		}
		var clear = function() {
			dataByValue.set({})
			dataByText.set({})
		}
		var lookup = function(itemString) {
			return get$c(dataByValue.get(), itemString).orThunk(function() {
				return get$c(dataByText.get(), itemString)
			})
		}
		var update = function(items) {
			var currentDataByValue = dataByValue.get()
			var currentDataByText = dataByText.get()
			var newDataByValue = {}
			var newDataByText = {}
			each$1(items, function(item) {
				newDataByValue[item.value] = item
				get$c(item, 'meta').each(function(meta) {
					get$c(meta, 'text').each(function(text) {
						newDataByText[text] = item
					})
				})
			})
			dataByValue.set(__assign(__assign({}, currentDataByValue), newDataByValue))
			dataByText.set(__assign(__assign({}, currentDataByText), newDataByText))
		}
		return nu$2({
			readState: readState,
			lookup: lookup,
			update: update,
			clear: clear
		})
	}
	var init$4 = function(spec) {
		return spec.store.manager.state(spec)
	}

	var RepresentState = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		memory: memory,
		dataset: dataset,
		manual: manual,
		init: init$4
	})

	var setValue$2 = function(component, repConfig, repState, data) {
		var store = repConfig.store
		repState.update([data])
		store.setValue(component, data)
		repConfig.onSetValue(component, data)
	}
	var getValue$3 = function(component, repConfig, repState) {
		var store = repConfig.store
		var key = store.getDataKey(component)
		return repState.lookup(key).getOrThunk(function() {
			return store.getFallbackEntry(key)
		})
	}
	var onLoad$3 = function(component, repConfig, repState) {
		var store = repConfig.store
		store.initialValue.each(function(data) {
			setValue$2(component, repConfig, repState, data)
		})
	}
	var onUnload$1 = function(component, repConfig, repState) {
		repState.clear()
	}
	var DatasetStore = [
		option('initialValue'),
		required$1('getFallbackEntry'),
		required$1('getDataKey'),
		required$1('setValue'),
		output('manager', {
			setValue: setValue$2,
			getValue: getValue$3,
			onLoad: onLoad$3,
			onUnload: onUnload$1,
			state: dataset
		})
	]

	var getValue$2 = function(component, repConfig, _repState) {
		return repConfig.store.getValue(component)
	}
	var setValue$1 = function(component, repConfig, _repState, data) {
		repConfig.store.setValue(component, data)
		repConfig.onSetValue(component, data)
	}
	var onLoad$2 = function(component, repConfig, _repState) {
		repConfig.store.initialValue.each(function(data) {
			repConfig.store.setValue(component, data)
		})
	}
	var ManualStore = [
		required$1('getValue'),
		defaulted('setValue', noop),
		option('initialValue'),
		output('manager', {
			setValue: setValue$1,
			getValue: getValue$2,
			onLoad: onLoad$2,
			onUnload: noop,
			state: NoState.init
		})
	]

	var setValue = function(component, repConfig, repState, data) {
		repState.set(data)
		repConfig.onSetValue(component, data)
	}
	var getValue$1 = function(component, repConfig, repState) {
		return repState.get()
	}
	var onLoad$1 = function(component, repConfig, repState) {
		repConfig.store.initialValue.each(function(initVal) {
			if (repState.isNotSet()) {
				repState.set(initVal)
			}
		})
	}
	var onUnload = function(component, repConfig, repState) {
		repState.clear()
	}
	var MemoryStore = [
		option('initialValue'),
		output('manager', {
			setValue: setValue,
			getValue: getValue$1,
			onLoad: onLoad$1,
			onUnload: onUnload,
			state: memory
		})
	]

	var RepresentSchema = [
		defaultedOf(
			'store',
			{ mode: 'memory' },
			choose$1('mode', {
				memory: MemoryStore,
				manual: ManualStore,
				dataset: DatasetStore
			})
		),
		onHandler('onSetValue'),
		defaulted('resetOnDom', false)
	]

	var Representing = create$5({
		fields: RepresentSchema,
		name: 'representing',
		active: ActiveRepresenting,
		apis: RepresentApis,
		extra: {
			setValueFrom: function(component, source) {
				var value = Representing.getValue(source)
				Representing.setValue(component, value)
			}
		},
		state: RepresentState
	})

	var api$1 = Dimension('width', function(element) {
		return element.dom.offsetWidth
	})
	var set$4 = function(element, h) {
		return api$1.set(element, h)
	}
	var get$5 = function(element) {
		return api$1.get(element)
	}

	var r$1 = function(left, top) {
		var translate = function(x, y) {
			return r$1(left + x, top + y)
		}
		return {
			left: left,
			top: top,
			translate: translate
		}
	}
	var SugarPosition = r$1

	var _sliderChangeEvent = 'slider.change.value'
	var sliderChangeEvent = constant$1(_sliderChangeEvent)
	var isTouchEvent = function(evt) {
		return evt.type.indexOf('touch') !== -1
	}
	var getEventSource = function(simulatedEvent) {
		var evt = simulatedEvent.event.raw
		if (isTouchEvent(evt)) {
			var touchEvent = evt
			return touchEvent.touches !== undefined && touchEvent.touches.length === 1
				? Optional.some(touchEvent.touches[0]).map(function(t) {
						return SugarPosition(t.clientX, t.clientY)
				  })
				: Optional.none()
		} else {
			var mouseEvent = evt
			return mouseEvent.clientX !== undefined
				? Optional.some(mouseEvent).map(function(me) {
						return SugarPosition(me.clientX, me.clientY)
				  })
				: Optional.none()
		}
	}

	var t = 'top',
		r = 'right',
		b = 'bottom',
		l = 'left'
	var minX = function(detail) {
		return detail.model.minX
	}
	var minY = function(detail) {
		return detail.model.minY
	}
	var min1X = function(detail) {
		return detail.model.minX - 1
	}
	var min1Y = function(detail) {
		return detail.model.minY - 1
	}
	var maxX = function(detail) {
		return detail.model.maxX
	}
	var maxY = function(detail) {
		return detail.model.maxY
	}
	var max1X = function(detail) {
		return detail.model.maxX + 1
	}
	var max1Y = function(detail) {
		return detail.model.maxY + 1
	}
	var range$1 = function(detail, max, min) {
		return max(detail) - min(detail)
	}
	var xRange = function(detail) {
		return range$1(detail, maxX, minX)
	}
	var yRange = function(detail) {
		return range$1(detail, maxY, minY)
	}
	var halfX = function(detail) {
		return xRange(detail) / 2
	}
	var halfY = function(detail) {
		return yRange(detail) / 2
	}
	var step = function(detail) {
		return detail.stepSize
	}
	var snap = function(detail) {
		return detail.snapToGrid
	}
	var snapStart = function(detail) {
		return detail.snapStart
	}
	var rounded = function(detail) {
		return detail.rounded
	}
	var hasEdge = function(detail, edgeName) {
		return detail[edgeName + '-edge'] !== undefined
	}
	var hasLEdge = function(detail) {
		return hasEdge(detail, l)
	}
	var hasREdge = function(detail) {
		return hasEdge(detail, r)
	}
	var hasTEdge = function(detail) {
		return hasEdge(detail, t)
	}
	var hasBEdge = function(detail) {
		return hasEdge(detail, b)
	}
	var currentValue = function(detail) {
		return detail.model.value.get()
	}

	var xValue = function(x) {
		return { x: x }
	}
	var yValue = function(y) {
		return { y: y }
	}
	var xyValue = function(x, y) {
		return {
			x: x,
			y: y
		}
	}
	var fireSliderChange$3 = function(component, value) {
		emitWith(component, sliderChangeEvent(), { value: value })
	}
	var setToTLEdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(min1X(detail), min1Y(detail)))
	}
	var setToTEdge = function(edge, detail) {
		fireSliderChange$3(edge, yValue(min1Y(detail)))
	}
	var setToTEdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(halfX(detail), min1Y(detail)))
	}
	var setToTREdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(max1X(detail), min1Y(detail)))
	}
	var setToREdge = function(edge, detail) {
		fireSliderChange$3(edge, xValue(max1X(detail)))
	}
	var setToREdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(max1X(detail), halfY(detail)))
	}
	var setToBREdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(max1X(detail), max1Y(detail)))
	}
	var setToBEdge = function(edge, detail) {
		fireSliderChange$3(edge, yValue(max1Y(detail)))
	}
	var setToBEdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(halfX(detail), max1Y(detail)))
	}
	var setToBLEdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(min1X(detail), max1Y(detail)))
	}
	var setToLEdge = function(edge, detail) {
		fireSliderChange$3(edge, xValue(min1X(detail)))
	}
	var setToLEdgeXY = function(edge, detail) {
		fireSliderChange$3(edge, xyValue(min1X(detail), halfY(detail)))
	}

	var reduceBy = function(value, min, max, step) {
		if (value < min) {
			return value
		} else if (value > max) {
			return max
		} else if (value === min) {
			return min - 1
		} else {
			return Math.max(min, value - step)
		}
	}
	var increaseBy = function(value, min, max, step) {
		if (value > max) {
			return value
		} else if (value < min) {
			return min
		} else if (value === max) {
			return max + 1
		} else {
			return Math.min(max, value + step)
		}
	}
	var capValue = function(value, min, max) {
		return Math.max(min, Math.min(max, value))
	}
	var snapValueOf = function(value, min, max, step, snapStart) {
		return snapStart.fold(
			function() {
				var initValue = value - min
				var extraValue = Math.round(initValue / step) * step
				return capValue(min + extraValue, min - 1, max + 1)
			},
			function(start) {
				var remainder = (value - start) % step
				var adjustment = Math.round(remainder / step)
				var rawSteps = Math.floor((value - start) / step)
				var maxSteps = Math.floor((max - start) / step)
				var numSteps = Math.min(maxSteps, rawSteps + adjustment)
				var r = start + numSteps * step
				return Math.max(start, r)
			}
		)
	}
	var findOffsetOf = function(value, min, max) {
		return Math.min(max, Math.max(value, min)) - min
	}
	var findValueOf = function(args) {
		var min = args.min,
			max = args.max,
			range = args.range,
			value = args.value,
			step = args.step,
			snap = args.snap,
			snapStart = args.snapStart,
			rounded = args.rounded,
			hasMinEdge = args.hasMinEdge,
			hasMaxEdge = args.hasMaxEdge,
			minBound = args.minBound,
			maxBound = args.maxBound,
			screenRange = args.screenRange
		var capMin = hasMinEdge ? min - 1 : min
		var capMax = hasMaxEdge ? max + 1 : max
		if (value < minBound) {
			return capMin
		} else if (value > maxBound) {
			return capMax
		} else {
			var offset = findOffsetOf(value, minBound, maxBound)
			var newValue = capValue((offset / screenRange) * range + min, capMin, capMax)
			if (snap && newValue >= min && newValue <= max) {
				return snapValueOf(newValue, min, max, step, snapStart)
			} else if (rounded) {
				return Math.round(newValue)
			} else {
				return newValue
			}
		}
	}
	var findOffsetOfValue$2 = function(args) {
		var min = args.min,
			max = args.max,
			range = args.range,
			value = args.value,
			hasMinEdge = args.hasMinEdge,
			hasMaxEdge = args.hasMaxEdge,
			maxBound = args.maxBound,
			maxOffset = args.maxOffset,
			centerMinEdge = args.centerMinEdge,
			centerMaxEdge = args.centerMaxEdge
		if (value < min) {
			return hasMinEdge ? 0 : centerMinEdge
		} else if (value > max) {
			return hasMaxEdge ? maxBound : centerMaxEdge
		} else {
			return ((value - min) / range) * maxOffset
		}
	}

	var top = 'top',
		right = 'right',
		bottom = 'bottom',
		left = 'left',
		width = 'width',
		height = 'height'
	var getBounds$1 = function(component) {
		return component.element.dom.getBoundingClientRect()
	}
	var getBoundsProperty = function(bounds, property) {
		return bounds[property]
	}
	var getMinXBounds = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, left)
	}
	var getMaxXBounds = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, right)
	}
	var getMinYBounds = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, top)
	}
	var getMaxYBounds = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, bottom)
	}
	var getXScreenRange = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, width)
	}
	var getYScreenRange = function(component) {
		var bounds = getBounds$1(component)
		return getBoundsProperty(bounds, height)
	}
	var getCenterOffsetOf = function(componentMinEdge, componentMaxEdge, spectrumMinEdge) {
		return (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge
	}
	var getXCenterOffSetOf = function(component, spectrum) {
		var componentBounds = getBounds$1(component)
		var spectrumBounds = getBounds$1(spectrum)
		var componentMinEdge = getBoundsProperty(componentBounds, left)
		var componentMaxEdge = getBoundsProperty(componentBounds, right)
		var spectrumMinEdge = getBoundsProperty(spectrumBounds, left)
		return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge)
	}
	var getYCenterOffSetOf = function(component, spectrum) {
		var componentBounds = getBounds$1(component)
		var spectrumBounds = getBounds$1(spectrum)
		var componentMinEdge = getBoundsProperty(componentBounds, top)
		var componentMaxEdge = getBoundsProperty(componentBounds, bottom)
		var spectrumMinEdge = getBoundsProperty(spectrumBounds, top)
		return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge)
	}

	var fireSliderChange$2 = function(spectrum, value) {
		emitWith(spectrum, sliderChangeEvent(), { value: value })
	}
	var sliderValue$2 = function(x) {
		return { x: x }
	}
	var findValueOfOffset$1 = function(spectrum, detail, left) {
		var args = {
			min: minX(detail),
			max: maxX(detail),
			range: xRange(detail),
			value: left,
			step: step(detail),
			snap: snap(detail),
			snapStart: snapStart(detail),
			rounded: rounded(detail),
			hasMinEdge: hasLEdge(detail),
			hasMaxEdge: hasREdge(detail),
			minBound: getMinXBounds(spectrum),
			maxBound: getMaxXBounds(spectrum),
			screenRange: getXScreenRange(spectrum)
		}
		return findValueOf(args)
	}
	var setValueFrom$2 = function(spectrum, detail, value) {
		var xValue = findValueOfOffset$1(spectrum, detail, value)
		var sliderVal = sliderValue$2(xValue)
		fireSliderChange$2(spectrum, sliderVal)
		return xValue
	}
	var setToMin$2 = function(spectrum, detail) {
		var min = minX(detail)
		fireSliderChange$2(spectrum, sliderValue$2(min))
	}
	var setToMax$2 = function(spectrum, detail) {
		var max = maxX(detail)
		fireSliderChange$2(spectrum, sliderValue$2(max))
	}
	var moveBy$2 = function(direction, spectrum, detail) {
		var f = direction > 0 ? increaseBy : reduceBy
		var xValue = f(currentValue(detail).x, minX(detail), maxX(detail), step(detail))
		fireSliderChange$2(spectrum, sliderValue$2(xValue))
		return Optional.some(xValue)
	}
	var handleMovement$2 = function(direction) {
		return function(spectrum, detail) {
			return moveBy$2(direction, spectrum, detail).map(always)
		}
	}
	var getValueFromEvent$2 = function(simulatedEvent) {
		var pos = getEventSource(simulatedEvent)
		return pos.map(function(p) {
			return p.left
		})
	}
	var findOffsetOfValue$1 = function(spectrum, detail, value, minEdge, maxEdge) {
		var minOffset = 0
		var maxOffset = getXScreenRange(spectrum)
		var centerMinEdge = minEdge
			.bind(function(edge) {
				return Optional.some(getXCenterOffSetOf(edge, spectrum))
			})
			.getOr(minOffset)
		var centerMaxEdge = maxEdge
			.bind(function(edge) {
				return Optional.some(getXCenterOffSetOf(edge, spectrum))
			})
			.getOr(maxOffset)
		var args = {
			min: minX(detail),
			max: maxX(detail),
			range: xRange(detail),
			value: value,
			hasMinEdge: hasLEdge(detail),
			hasMaxEdge: hasREdge(detail),
			minBound: getMinXBounds(spectrum),
			minOffset: minOffset,
			maxBound: getMaxXBounds(spectrum),
			maxOffset: maxOffset,
			centerMinEdge: centerMinEdge,
			centerMaxEdge: centerMaxEdge
		}
		return findOffsetOfValue$2(args)
	}
	var findPositionOfValue$1 = function(slider, spectrum, value, minEdge, maxEdge, detail) {
		var offset = findOffsetOfValue$1(spectrum, detail, value, minEdge, maxEdge)
		return getMinXBounds(spectrum) - getMinXBounds(slider) + offset
	}
	var setPositionFromValue$2 = function(slider, thumb, detail, edges) {
		var value = currentValue(detail)
		var pos = findPositionOfValue$1(
			slider,
			edges.getSpectrum(slider),
			value.x,
			edges.getLeftEdge(slider),
			edges.getRightEdge(slider),
			detail
		)
		var thumbRadius = get$5(thumb.element) / 2
		set$5(thumb.element, 'left', pos - thumbRadius + 'px')
	}
	var onLeft$2 = handleMovement$2(-1)
	var onRight$2 = handleMovement$2(1)
	var onUp$2 = Optional.none
	var onDown$2 = Optional.none
	var edgeActions$2 = {
		'top-left': Optional.none(),
		top: Optional.none(),
		'top-right': Optional.none(),
		right: Optional.some(setToREdge),
		'bottom-right': Optional.none(),
		bottom: Optional.none(),
		'bottom-left': Optional.none(),
		left: Optional.some(setToLEdge)
	}

	var HorizontalModel = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		setValueFrom: setValueFrom$2,
		setToMin: setToMin$2,
		setToMax: setToMax$2,
		findValueOfOffset: findValueOfOffset$1,
		getValueFromEvent: getValueFromEvent$2,
		findPositionOfValue: findPositionOfValue$1,
		setPositionFromValue: setPositionFromValue$2,
		onLeft: onLeft$2,
		onRight: onRight$2,
		onUp: onUp$2,
		onDown: onDown$2,
		edgeActions: edgeActions$2
	})

	var fireSliderChange$1 = function(spectrum, value) {
		emitWith(spectrum, sliderChangeEvent(), { value: value })
	}
	var sliderValue$1 = function(y) {
		return { y: y }
	}
	var findValueOfOffset = function(spectrum, detail, top) {
		var args = {
			min: minY(detail),
			max: maxY(detail),
			range: yRange(detail),
			value: top,
			step: step(detail),
			snap: snap(detail),
			snapStart: snapStart(detail),
			rounded: rounded(detail),
			hasMinEdge: hasTEdge(detail),
			hasMaxEdge: hasBEdge(detail),
			minBound: getMinYBounds(spectrum),
			maxBound: getMaxYBounds(spectrum),
			screenRange: getYScreenRange(spectrum)
		}
		return findValueOf(args)
	}
	var setValueFrom$1 = function(spectrum, detail, value) {
		var yValue = findValueOfOffset(spectrum, detail, value)
		var sliderVal = sliderValue$1(yValue)
		fireSliderChange$1(spectrum, sliderVal)
		return yValue
	}
	var setToMin$1 = function(spectrum, detail) {
		var min = minY(detail)
		fireSliderChange$1(spectrum, sliderValue$1(min))
	}
	var setToMax$1 = function(spectrum, detail) {
		var max = maxY(detail)
		fireSliderChange$1(spectrum, sliderValue$1(max))
	}
	var moveBy$1 = function(direction, spectrum, detail) {
		var f = direction > 0 ? increaseBy : reduceBy
		var yValue = f(currentValue(detail).y, minY(detail), maxY(detail), step(detail))
		fireSliderChange$1(spectrum, sliderValue$1(yValue))
		return Optional.some(yValue)
	}
	var handleMovement$1 = function(direction) {
		return function(spectrum, detail) {
			return moveBy$1(direction, spectrum, detail).map(always)
		}
	}
	var getValueFromEvent$1 = function(simulatedEvent) {
		var pos = getEventSource(simulatedEvent)
		return pos.map(function(p) {
			return p.top
		})
	}
	var findOffsetOfValue = function(spectrum, detail, value, minEdge, maxEdge) {
		var minOffset = 0
		var maxOffset = getYScreenRange(spectrum)
		var centerMinEdge = minEdge
			.bind(function(edge) {
				return Optional.some(getYCenterOffSetOf(edge, spectrum))
			})
			.getOr(minOffset)
		var centerMaxEdge = maxEdge
			.bind(function(edge) {
				return Optional.some(getYCenterOffSetOf(edge, spectrum))
			})
			.getOr(maxOffset)
		var args = {
			min: minY(detail),
			max: maxY(detail),
			range: yRange(detail),
			value: value,
			hasMinEdge: hasTEdge(detail),
			hasMaxEdge: hasBEdge(detail),
			minBound: getMinYBounds(spectrum),
			minOffset: minOffset,
			maxBound: getMaxYBounds(spectrum),
			maxOffset: maxOffset,
			centerMinEdge: centerMinEdge,
			centerMaxEdge: centerMaxEdge
		}
		return findOffsetOfValue$2(args)
	}
	var findPositionOfValue = function(slider, spectrum, value, minEdge, maxEdge, detail) {
		var offset = findOffsetOfValue(spectrum, detail, value, minEdge, maxEdge)
		return getMinYBounds(spectrum) - getMinYBounds(slider) + offset
	}
	var setPositionFromValue$1 = function(slider, thumb, detail, edges) {
		var value = currentValue(detail)
		var pos = findPositionOfValue(
			slider,
			edges.getSpectrum(slider),
			value.y,
			edges.getTopEdge(slider),
			edges.getBottomEdge(slider),
			detail
		)
		var thumbRadius = get$7(thumb.element) / 2
		set$5(thumb.element, 'top', pos - thumbRadius + 'px')
	}
	var onLeft$1 = Optional.none
	var onRight$1 = Optional.none
	var onUp$1 = handleMovement$1(-1)
	var onDown$1 = handleMovement$1(1)
	var edgeActions$1 = {
		'top-left': Optional.none(),
		top: Optional.some(setToTEdge),
		'top-right': Optional.none(),
		right: Optional.none(),
		'bottom-right': Optional.none(),
		bottom: Optional.some(setToBEdge),
		'bottom-left': Optional.none(),
		left: Optional.none()
	}

	var VerticalModel = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		setValueFrom: setValueFrom$1,
		setToMin: setToMin$1,
		setToMax: setToMax$1,
		findValueOfOffset: findValueOfOffset,
		getValueFromEvent: getValueFromEvent$1,
		findPositionOfValue: findPositionOfValue,
		setPositionFromValue: setPositionFromValue$1,
		onLeft: onLeft$1,
		onRight: onRight$1,
		onUp: onUp$1,
		onDown: onDown$1,
		edgeActions: edgeActions$1
	})

	var fireSliderChange = function(spectrum, value) {
		emitWith(spectrum, sliderChangeEvent(), { value: value })
	}
	var sliderValue = function(x, y) {
		return {
			x: x,
			y: y
		}
	}
	var setValueFrom = function(spectrum, detail, value) {
		var xValue = findValueOfOffset$1(spectrum, detail, value.left)
		var yValue = findValueOfOffset(spectrum, detail, value.top)
		var val = sliderValue(xValue, yValue)
		fireSliderChange(spectrum, val)
		return val
	}
	var moveBy = function(direction, isVerticalMovement, spectrum, detail) {
		var f = direction > 0 ? increaseBy : reduceBy
		var xValue = isVerticalMovement
			? currentValue(detail).x
			: f(currentValue(detail).x, minX(detail), maxX(detail), step(detail))
		var yValue = !isVerticalMovement
			? currentValue(detail).y
			: f(currentValue(detail).y, minY(detail), maxY(detail), step(detail))
		fireSliderChange(spectrum, sliderValue(xValue, yValue))
		return Optional.some(xValue)
	}
	var handleMovement = function(direction, isVerticalMovement) {
		return function(spectrum, detail) {
			return moveBy(direction, isVerticalMovement, spectrum, detail).map(always)
		}
	}
	var setToMin = function(spectrum, detail) {
		var mX = minX(detail)
		var mY = minY(detail)
		fireSliderChange(spectrum, sliderValue(mX, mY))
	}
	var setToMax = function(spectrum, detail) {
		var mX = maxX(detail)
		var mY = maxY(detail)
		fireSliderChange(spectrum, sliderValue(mX, mY))
	}
	var getValueFromEvent = function(simulatedEvent) {
		return getEventSource(simulatedEvent)
	}
	var setPositionFromValue = function(slider, thumb, detail, edges) {
		var value = currentValue(detail)
		var xPos = findPositionOfValue$1(
			slider,
			edges.getSpectrum(slider),
			value.x,
			edges.getLeftEdge(slider),
			edges.getRightEdge(slider),
			detail
		)
		var yPos = findPositionOfValue(
			slider,
			edges.getSpectrum(slider),
			value.y,
			edges.getTopEdge(slider),
			edges.getBottomEdge(slider),
			detail
		)
		var thumbXRadius = get$5(thumb.element) / 2
		var thumbYRadius = get$7(thumb.element) / 2
		set$5(thumb.element, 'left', xPos - thumbXRadius + 'px')
		set$5(thumb.element, 'top', yPos - thumbYRadius + 'px')
	}
	var onLeft = handleMovement(-1, false)
	var onRight = handleMovement(1, false)
	var onUp = handleMovement(-1, true)
	var onDown = handleMovement(1, true)
	var edgeActions = {
		'top-left': Optional.some(setToTLEdgeXY),
		top: Optional.some(setToTEdgeXY),
		'top-right': Optional.some(setToTREdgeXY),
		right: Optional.some(setToREdgeXY),
		'bottom-right': Optional.some(setToBREdgeXY),
		bottom: Optional.some(setToBEdgeXY),
		'bottom-left': Optional.some(setToBLEdgeXY),
		left: Optional.some(setToLEdgeXY)
	}

	var TwoDModel = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		setValueFrom: setValueFrom,
		setToMin: setToMin,
		setToMax: setToMax,
		getValueFromEvent: getValueFromEvent,
		setPositionFromValue: setPositionFromValue,
		onLeft: onLeft,
		onRight: onRight,
		onUp: onUp,
		onDown: onDown,
		edgeActions: edgeActions
	})

	var SliderSchema = [
		defaulted('stepSize', 1),
		defaulted('onChange', noop),
		defaulted('onChoose', noop),
		defaulted('onInit', noop),
		defaulted('onDragStart', noop),
		defaulted('onDragEnd', noop),
		defaulted('snapToGrid', false),
		defaulted('rounded', true),
		option('snapStart'),
		requiredOf(
			'model',
			choose$1('mode', {
				x: [
					defaulted('minX', 0),
					defaulted('maxX', 100),
					customField('value', function(spec) {
						return Cell(spec.mode.minX)
					}),
					required$1('getInitialValue'),
					output('manager', HorizontalModel)
				],
				y: [
					defaulted('minY', 0),
					defaulted('maxY', 100),
					customField('value', function(spec) {
						return Cell(spec.mode.minY)
					}),
					required$1('getInitialValue'),
					output('manager', VerticalModel)
				],
				xy: [
					defaulted('minX', 0),
					defaulted('maxX', 100),
					defaulted('minY', 0),
					defaulted('maxY', 100),
					customField('value', function(spec) {
						return Cell({
							x: spec.mode.minX,
							y: spec.mode.minY
						})
					}),
					required$1('getInitialValue'),
					output('manager', TwoDModel)
				]
			})
		),
		field$1('sliderBehaviours', [Keying, Representing]),
		customField('mouseIsDown', function() {
			return Cell(false)
		})
	]

	var mouseReleased = constant$1('mouse.released')

	var sketch$9 = function(detail, components, _spec, _externals) {
		var _a
		var getThumb = function(component) {
			return getPartOrDie(component, detail, 'thumb')
		}
		var getSpectrum = function(component) {
			return getPartOrDie(component, detail, 'spectrum')
		}
		var getLeftEdge = function(component) {
			return getPart(component, detail, 'left-edge')
		}
		var getRightEdge = function(component) {
			return getPart(component, detail, 'right-edge')
		}
		var getTopEdge = function(component) {
			return getPart(component, detail, 'top-edge')
		}
		var getBottomEdge = function(component) {
			return getPart(component, detail, 'bottom-edge')
		}
		var modelDetail = detail.model
		var model = modelDetail.manager
		var refresh = function(slider, thumb) {
			model.setPositionFromValue(slider, thumb, detail, {
				getLeftEdge: getLeftEdge,
				getRightEdge: getRightEdge,
				getTopEdge: getTopEdge,
				getBottomEdge: getBottomEdge,
				getSpectrum: getSpectrum
			})
		}
		var setValue = function(slider, newValue) {
			modelDetail.value.set(newValue)
			var thumb = getThumb(slider)
			refresh(slider, thumb)
		}
		var changeValue = function(slider, newValue) {
			setValue(slider, newValue)
			var thumb = getThumb(slider)
			detail.onChange(slider, thumb, newValue)
			return Optional.some(true)
		}
		var resetToMin = function(slider) {
			model.setToMin(slider, detail)
		}
		var resetToMax = function(slider) {
			model.setToMax(slider, detail)
		}
		var choose = function(slider) {
			var fireOnChoose = function() {
				getPart(slider, detail, 'thumb').each(function(thumb) {
					var value = modelDetail.value.get()
					detail.onChoose(slider, thumb, value)
				})
			}
			var wasDown = detail.mouseIsDown.get()
			detail.mouseIsDown.set(false)
			if (wasDown) {
				fireOnChoose()
			}
		}
		var onDragStart = function(slider, simulatedEvent) {
			simulatedEvent.stop()
			detail.mouseIsDown.set(true)
			detail.onDragStart(slider, getThumb(slider))
		}
		var onDragEnd = function(slider, simulatedEvent) {
			simulatedEvent.stop()
			detail.onDragEnd(slider, getThumb(slider))
			choose(slider)
		}
		return {
			uid: detail.uid,
			dom: detail.dom,
			components: components,
			behaviours: augment(detail.sliderBehaviours, [
				Keying.config({
					mode: 'special',
					focusIn: function(slider) {
						return getPart(slider, detail, 'spectrum')
							.map(Keying.focusIn)
							.map(always)
					}
				}),
				Representing.config({
					store: {
						mode: 'manual',
						getValue: function(_) {
							return modelDetail.value.get()
						}
					}
				}),
				Receiving.config({ channels: ((_a = {}), (_a[mouseReleased()] = { onReceive: choose }), _a) })
			]),
			events: derive$3([
				run(sliderChangeEvent(), function(slider, simulatedEvent) {
					changeValue(slider, simulatedEvent.event.value)
				}),
				runOnAttached(function(slider, _simulatedEvent) {
					var getInitial = modelDetail.getInitialValue()
					modelDetail.value.set(getInitial)
					var thumb = getThumb(slider)
					refresh(slider, thumb)
					var spectrum = getSpectrum(slider)
					detail.onInit(slider, thumb, spectrum, modelDetail.value.get())
				}),
				run(touchstart(), onDragStart),
				run(touchend(), onDragEnd),
				run(mousedown(), onDragStart),
				run(mouseup(), onDragEnd)
			]),
			apis: {
				resetToMin: resetToMin,
				resetToMax: resetToMax,
				setValue: setValue,
				refresh: refresh
			},
			domModification: { styles: { position: 'relative' } }
		}
	}

	var Slider = composite({
		name: 'Slider',
		configFields: SliderSchema,
		partFields: SliderParts,
		factory: sketch$9,
		apis: {
			setValue: function(apis, slider, value) {
				apis.setValue(slider, value)
			},
			resetToMin: function(apis, slider) {
				apis.resetToMin(slider)
			},
			resetToMax: function(apis, slider) {
				apis.resetToMax(slider)
			},
			refresh: function(apis, slider) {
				apis.refresh(slider)
			}
		}
	})

	var button = function(realm, clazz, makeItems, editor) {
		return forToolbar(
			clazz,
			function() {
				var items = makeItems()
				realm.setContextToolbar([
					{
						label: clazz + ' group',
						items: items
					}
				])
			},
			{},
			editor
		)
	}

	var BLACK = -1
	var makeSlider$1 = function(spec$1) {
		var getColor = function(hue) {
			if (hue < 0) {
				return 'black'
			} else if (hue > 360) {
				return 'white'
			} else {
				return 'hsl(' + hue + ', 100%, 50%)'
			}
		}
		var onInit = function(slider, thumb, spectrum, value) {
			var color = getColor(value.x())
			set$5(thumb.element, 'background-color', color)
		}
		var onChange = function(slider, thumb, value) {
			var color = getColor(value.x())
			set$5(thumb.element, 'background-color', color)
			spec$1.onChange(slider, thumb, color)
		}
		return Slider.sketch({
			dom: dom$1('<div class="${prefix}-slider ${prefix}-hue-slider-container"></div>'),
			components: [
				Slider.parts['left-edge'](spec('<div class="${prefix}-hue-slider-black"></div>')),
				Slider.parts.spectrum({
					dom: dom$1('<div class="${prefix}-slider-gradient-container"></div>'),
					components: [spec('<div class="${prefix}-slider-gradient"></div>')],
					behaviours: derive$2([Toggling.config({ toggleClass: resolve('thumb-active') })])
				}),
				Slider.parts['right-edge'](spec('<div class="${prefix}-hue-slider-white"></div>')),
				Slider.parts.thumb({
					dom: dom$1('<div class="${prefix}-slider-thumb"></div>'),
					behaviours: derive$2([Toggling.config({ toggleClass: resolve('thumb-active') })])
				})
			],
			onChange: onChange,
			onDragStart: function(slider, thumb) {
				Toggling.on(thumb)
			},
			onDragEnd: function(slider, thumb) {
				Toggling.off(thumb)
			},
			onInit: onInit,
			stepSize: 10,
			model: {
				mode: 'x',
				minX: 0,
				maxX: 360,
				getInitialValue: function() {
					return { x: spec$1.getInitialValue() }
				}
			},
			sliderBehaviours: derive$2([orientation(Slider.refresh)])
		})
	}
	var makeItems$1 = function(spec) {
		return [makeSlider$1(spec)]
	}
	var sketch$8 = function(realm, editor) {
		var spec = {
			onChange: function(slider, thumb, color) {
				editor.undoManager.transact(function() {
					editor.formatter.apply('forecolor', { value: color })
					editor.nodeChanged()
				})
			},
			getInitialValue: constant$1(BLACK)
		}
		return button(
			realm,
			'color-levels',
			function() {
				return makeItems$1(spec)
			},
			editor
		)
	}

	var candidatesArray = ['9px', '10px', '11px', '12px', '14px', '16px', '18px', '20px', '24px', '32px', '36px']
	var defaultSize = 'medium'
	var defaultIndex = 2
	var indexToSize = function(index) {
		return Optional.from(candidatesArray[index])
	}
	var sizeToIndex = function(size) {
		return findIndex$1(candidatesArray, function(v) {
			return v === size
		})
	}
	var getRawOrComputed = function(isRoot, rawStart) {
		var optStart = isElement(rawStart) ? Optional.some(rawStart) : parent(rawStart).filter(isElement)
		return optStart
			.map(function(start) {
				var inline = closest$2(
					start,
					function(elem) {
						return getRaw(elem, 'font-size').isSome()
					},
					isRoot
				).bind(function(elem) {
					return getRaw(elem, 'font-size')
				})
				return inline.getOrThunk(function() {
					return get$8(start, 'font-size')
				})
			})
			.getOr('')
	}
	var getSize = function(editor) {
		var node = editor.selection.getStart()
		var elem = SugarElement.fromDom(node)
		var root = SugarElement.fromDom(editor.getBody())
		var isRoot = function(e) {
			return eq(root, e)
		}
		var elemSize = getRawOrComputed(isRoot, elem)
		return find$2(candidatesArray, function(size) {
			return elemSize === size
		}).getOr(defaultSize)
	}
	var applySize = function(editor, value) {
		var currentValue = getSize(editor)
		if (currentValue !== value) {
			editor.execCommand('fontSize', false, value)
		}
	}
	var get$4 = function(editor) {
		var size = getSize(editor)
		return sizeToIndex(size).getOr(defaultIndex)
	}
	var apply = function(editor, index) {
		indexToSize(index).each(function(size) {
			applySize(editor, size)
		})
	}
	var candidates = constant$1(candidatesArray)

	var schema$9 = objOfOnly([
		required$1('getInitialValue'),
		required$1('onChange'),
		required$1('category'),
		required$1('sizes')
	])
	var sketch$7 = function(rawSpec) {
		var spec$1 = asRawOrDie$1('SizeSlider', schema$9, rawSpec)
		var isValidValue = function(valueIndex) {
			return valueIndex >= 0 && valueIndex < spec$1.sizes.length
		}
		var onChange = function(slider, thumb, valueIndex) {
			var index = valueIndex.x()
			if (isValidValue(index)) {
				spec$1.onChange(index)
			}
		}
		return Slider.sketch({
			dom: {
				tag: 'div',
				classes: [
					resolve('slider-' + spec$1.category + '-size-container'),
					resolve('slider'),
					resolve('slider-size-container')
				]
			},
			onChange: onChange,
			onDragStart: function(slider, thumb) {
				Toggling.on(thumb)
			},
			onDragEnd: function(slider, thumb) {
				Toggling.off(thumb)
			},
			model: {
				mode: 'x',
				minX: 0,
				maxX: spec$1.sizes.length - 1,
				getInitialValue: function() {
					return { x: spec$1.getInitialValue() }
				}
			},
			stepSize: 1,
			snapToGrid: true,
			sliderBehaviours: derive$2([orientation(Slider.refresh)]),
			components: [
				Slider.parts.spectrum({
					dom: dom$1('<div class="${prefix}-slider-size-container"></div>'),
					components: [spec('<div class="${prefix}-slider-size-line"></div>')]
				}),
				Slider.parts.thumb({
					dom: dom$1('<div class="${prefix}-slider-thumb"></div>'),
					behaviours: derive$2([Toggling.config({ toggleClass: resolve('thumb-active') })])
				})
			]
		})
	}

	var sizes = candidates()
	var makeSlider = function(spec) {
		return sketch$7({
			onChange: spec.onChange,
			sizes: sizes,
			category: 'font',
			getInitialValue: spec.getInitialValue
		})
	}
	var makeItems = function(spec$1) {
		return [
			spec('<span class="${prefix}-toolbar-button ${prefix}-icon-small-font ${prefix}-icon"></span>'),
			makeSlider(spec$1),
			spec('<span class="${prefix}-toolbar-button ${prefix}-icon-large-font ${prefix}-icon"></span>')
		]
	}
	var sketch$6 = function(realm, editor) {
		var spec = {
			onChange: function(value) {
				apply(editor, value)
			},
			getInitialValue: function() {
				return get$4(editor)
			}
		}
		return button(
			realm,
			'font-size',
			function() {
				return makeItems(spec)
			},
			editor
		)
	}

	var record = function(spec) {
		var uid = isSketchSpec$1(spec) && hasNonNullableKey(spec, 'uid') ? spec.uid : generate$2('memento')
		var get = function(anyInSystem) {
			return anyInSystem
				.getSystem()
				.getByUid(uid)
				.getOrDie()
		}
		var getOpt = function(anyInSystem) {
			return anyInSystem
				.getSystem()
				.getByUid(uid)
				.toOptional()
		}
		var asSpec = function() {
			return __assign(__assign({}, spec), { uid: uid })
		}
		return {
			get: get,
			getOpt: getOpt,
			asSpec: asSpec
		}
	}

	var exports$1 = {},
		module = { exports: exports$1 }
	;(function(define, exports, module, require) {
		;(function(global, factory) {
			typeof exports === 'object' && typeof module !== 'undefined'
				? (module.exports = factory())
				: typeof define === 'function' && define.amd
				? define(factory)
				: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
				  (global.EphoxContactWrapper = factory()))
		})(this, function() {
			var commonjsGlobal =
				typeof globalThis !== 'undefined'
					? globalThis
					: typeof window !== 'undefined'
					? window
					: typeof global !== 'undefined'
					? global
					: typeof self !== 'undefined'
					? self
					: {}
			var promise = { exports: {} }
			;(function(module) {
				;(function(root) {
					var setTimeoutFunc = setTimeout
					function noop() {}
					function bind(fn, thisArg) {
						return function() {
							fn.apply(thisArg, arguments)
						}
					}
					function Promise(fn) {
						if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new')
						if (typeof fn !== 'function') throw new TypeError('not a function')
						this._state = 0
						this._handled = false
						this._value = undefined
						this._deferreds = []
						doResolve(fn, this)
					}
					function handle(self, deferred) {
						while (self._state === 3) {
							self = self._value
						}
						if (self._state === 0) {
							self._deferreds.push(deferred)
							return
						}
						self._handled = true
						Promise._immediateFn(function() {
							var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected
							if (cb === null) {
								;(self._state === 1 ? resolve : reject)(deferred.promise, self._value)
								return
							}
							var ret
							try {
								ret = cb(self._value)
							} catch (e) {
								reject(deferred.promise, e)
								return
							}
							resolve(deferred.promise, ret)
						})
					}
					function resolve(self, newValue) {
						try {
							if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.')
							if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
								var then = newValue.then
								if (newValue instanceof Promise) {
									self._state = 3
									self._value = newValue
									finale(self)
									return
								} else if (typeof then === 'function') {
									doResolve(bind(then, newValue), self)
									return
								}
							}
							self._state = 1
							self._value = newValue
							finale(self)
						} catch (e) {
							reject(self, e)
						}
					}
					function reject(self, newValue) {
						self._state = 2
						self._value = newValue
						finale(self)
					}
					function finale(self) {
						if (self._state === 2 && self._deferreds.length === 0) {
							Promise._immediateFn(function() {
								if (!self._handled) {
									Promise._unhandledRejectionFn(self._value)
								}
							})
						}
						for (var i = 0, len = self._deferreds.length; i < len; i++) {
							handle(self, self._deferreds[i])
						}
						self._deferreds = null
					}
					function Handler(onFulfilled, onRejected, promise) {
						this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
						this.onRejected = typeof onRejected === 'function' ? onRejected : null
						this.promise = promise
					}
					function doResolve(fn, self) {
						var done = false
						try {
							fn(
								function(value) {
									if (done) return
									done = true
									resolve(self, value)
								},
								function(reason) {
									if (done) return
									done = true
									reject(self, reason)
								}
							)
						} catch (ex) {
							if (done) return
							done = true
							reject(self, ex)
						}
					}
					Promise.prototype['catch'] = function(onRejected) {
						return this.then(null, onRejected)
					}
					Promise.prototype.then = function(onFulfilled, onRejected) {
						var prom = new this.constructor(noop)
						handle(this, new Handler(onFulfilled, onRejected, prom))
						return prom
					}
					Promise.all = function(arr) {
						var args = Array.prototype.slice.call(arr)
						return new Promise(function(resolve, reject) {
							if (args.length === 0) return resolve([])
							var remaining = args.length
							function res(i, val) {
								try {
									if (val && (typeof val === 'object' || typeof val === 'function')) {
										var then = val.then
										if (typeof then === 'function') {
											then.call(
												val,
												function(val) {
													res(i, val)
												},
												reject
											)
											return
										}
									}
									args[i] = val
									if (--remaining === 0) {
										resolve(args)
									}
								} catch (ex) {
									reject(ex)
								}
							}
							for (var i = 0; i < args.length; i++) {
								res(i, args[i])
							}
						})
					}
					Promise.resolve = function(value) {
						if (value && typeof value === 'object' && value.constructor === Promise) {
							return value
						}
						return new Promise(function(resolve) {
							resolve(value)
						})
					}
					Promise.reject = function(value) {
						return new Promise(function(resolve, reject) {
							reject(value)
						})
					}
					Promise.race = function(values) {
						return new Promise(function(resolve, reject) {
							for (var i = 0, len = values.length; i < len; i++) {
								values[i].then(resolve, reject)
							}
						})
					}
					Promise._immediateFn =
						typeof setImmediate === 'function'
							? function(fn) {
									setImmediate(fn)
							  }
							: function(fn) {
									setTimeoutFunc(fn, 0)
							  }
					Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
						if (typeof console !== 'undefined' && console) {
							console.warn('Possible Unhandled Promise Rejection:', err)
						}
					}
					Promise._setImmediateFn = function _setImmediateFn(fn) {
						Promise._immediateFn = fn
					}
					Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
						Promise._unhandledRejectionFn = fn
					}
					if (module.exports) {
						module.exports = Promise
					} else if (!root.Promise) {
						root.Promise = Promise
					}
				})(commonjsGlobal)
			})(promise)
			var promisePolyfill = promise.exports
			var Global = (function() {
				if (typeof window !== 'undefined') {
					return window
				} else {
					return Function('return this;')()
				}
			})()
			var promisePolyfill_1 = { boltExport: Global.Promise || promisePolyfill }
			return promisePolyfill_1
		})
	})(undefined, exports$1, module)
	var Promise$1 = module.exports.boltExport

	var blobToDataUri = function(blob) {
		return new Promise$1(function(resolve) {
			var reader = new FileReader()
			reader.onloadend = function() {
				resolve(reader.result)
			}
			reader.readAsDataURL(blob)
		})
	}
	var blobToBase64$1 = function(blob) {
		return blobToDataUri(blob).then(function(dataUri) {
			return dataUri.split(',')[1]
		})
	}

	var blobToBase64 = function(blob) {
		return blobToBase64$1(blob)
	}

	var addImage = function(editor, blob) {
		blobToBase64(blob).then(function(base64) {
			editor.undoManager.transact(function() {
				var cache = editor.editorUpload.blobCache
				var info = cache.create(generate$4('mceu'), blob, base64)
				cache.add(info)
				var img = editor.dom.createHTML('img', { src: info.blobUri() })
				editor.insertContent(img)
			})
		})
	}
	var extractBlob = function(simulatedEvent) {
		var event = simulatedEvent.event.raw
		var files = event.target.files || event.dataTransfer.files
		return Optional.from(files[0])
	}
	var sketch$5 = function(editor) {
		var pickerDom = {
			tag: 'input',
			attributes: {
				accept: 'image/*',
				type: 'file',
				title: ''
			},
			styles: {
				visibility: 'hidden',
				position: 'absolute'
			}
		}
		var memPicker = record({
			dom: pickerDom,
			events: derive$3([
				cutter(click()),
				run(change(), function(picker, simulatedEvent) {
					extractBlob(simulatedEvent).each(function(blob) {
						addImage(editor, blob)
					})
				})
			])
		})
		return Button.sketch({
			dom: getToolbarIconButton('image', editor),
			components: [memPicker.asSpec()],
			action: function(button) {
				var picker = memPicker.get(button)
				picker.element.dom.click()
			}
		})
	}

	var get$3 = function(element) {
		return element.dom.textContent
	}
	var set$3 = function(element, value) {
		element.dom.textContent = value
	}

	var isNotEmpty = function(val) {
		return val.length > 0
	}
	var defaultToEmpty = function(str) {
		return str === undefined || str === null ? '' : str
	}
	var noLink = function(editor) {
		var text = editor.selection.getContent({ format: 'text' })
		return {
			url: '',
			text: text,
			title: '',
			target: '',
			link: Optional.none()
		}
	}
	var fromLink = function(link) {
		var text = get$3(link)
		var url = get$b(link, 'href')
		var title = get$b(link, 'title')
		var target = get$b(link, 'target')
		return {
			url: defaultToEmpty(url),
			text: text !== url ? defaultToEmpty(text) : '',
			title: defaultToEmpty(title),
			target: defaultToEmpty(target),
			link: Optional.some(link)
		}
	}
	var getInfo = function(editor) {
		return query(editor).fold(
			function() {
				return noLink(editor)
			},
			function(link) {
				return fromLink(link)
			}
		)
	}
	var wasSimple = function(link) {
		var prevHref = get$b(link, 'href')
		var prevText = get$3(link)
		return prevHref === prevText
	}
	var getTextToApply = function(link, url, info) {
		return info.text
			.toOptional()
			.filter(isNotEmpty)
			.fold(function() {
				return wasSimple(link) ? Optional.some(url) : Optional.none()
			}, Optional.some)
	}
	var unlinkIfRequired = function(editor, info) {
		var activeLink = info.link.bind(identity)
		activeLink.each(function(_link) {
			editor.execCommand('unlink')
		})
	}
	var getAttrs = function(url, info) {
		var attrs = {}
		attrs.href = url
		info.title
			.toOptional()
			.filter(isNotEmpty)
			.each(function(title) {
				attrs.title = title
			})
		info.target
			.toOptional()
			.filter(isNotEmpty)
			.each(function(target) {
				attrs.target = target
			})
		return attrs
	}
	var applyInfo = function(editor, info) {
		info.url
			.toOptional()
			.filter(isNotEmpty)
			.fold(
				function() {
					unlinkIfRequired(editor, info)
				},
				function(url) {
					var attrs = getAttrs(url, info)
					var activeLink = info.link.bind(identity)
					activeLink.fold(
						function() {
							var text = info.text
								.toOptional()
								.filter(isNotEmpty)
								.getOr(url)
							editor.insertContent(editor.dom.createHTML('a', attrs, editor.dom.encode(text)))
						},
						function(link) {
							var text = getTextToApply(link, url, info)
							setAll$1(link, attrs)
							text.each(function(newText) {
								set$3(link, newText)
							})
						}
					)
				}
			)
	}
	var query = function(editor) {
		var start = SugarElement.fromDom(editor.selection.getStart())
		return closest$1(start, 'a')
	}

	var platform = detect$1()
	var preserve$1 = function(f, editor) {
		var rng = editor.selection.getRng()
		f()
		editor.selection.setRng(rng)
	}
	var forAndroid = function(editor, f) {
		var wrapper = platform.os.isAndroid() ? preserve$1 : apply$1
		wrapper(f, editor)
	}

	var events$4 = function(name, eventHandlers) {
		var events = derive$3(eventHandlers)
		return create$5({
			fields: [required$1('enabled')],
			name: name,
			active: { events: constant$1(events) }
		})
	}
	var config = function(name, eventHandlers) {
		var me = events$4(name, eventHandlers)
		return {
			key: name,
			value: {
				config: {},
				me: me,
				configAsRaw: constant$1({}),
				initialConfig: {},
				state: NoState
			}
		}
	}

	var getCurrent = function(component, composeConfig, _composeState) {
		return composeConfig.find(component)
	}

	var ComposeApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		getCurrent: getCurrent
	})

	var ComposeSchema = [required$1('find')]

	var Composing = create$5({
		fields: ComposeSchema,
		name: 'composing',
		apis: ComposeApis
	})

	var factory$4 = function(detail) {
		var _a = detail.dom,
			attributes = _a.attributes,
			domWithoutAttributes = __rest(_a, ['attributes'])
		return {
			uid: detail.uid,
			dom: __assign(
				{
					tag: 'div',
					attributes: __assign({ role: 'presentation' }, attributes)
				},
				domWithoutAttributes
			),
			components: detail.components,
			behaviours: get$6(detail.containerBehaviours),
			events: detail.events,
			domModification: detail.domModification,
			eventOrder: detail.eventOrder
		}
	}
	var Container = single({
		name: 'Container',
		factory: factory$4,
		configFields: [
			defaulted('components', []),
			field$1('containerBehaviours', []),
			defaulted('events', {}),
			defaulted('domModification', {}),
			defaulted('eventOrder', {})
		]
	})

	var factory$3 = function(detail) {
		return {
			uid: detail.uid,
			dom: detail.dom,
			behaviours: SketchBehaviours.augment(detail.dataBehaviours, [
				Representing.config({
					store: {
						mode: 'memory',
						initialValue: detail.getInitialValue()
					}
				}),
				Composing.config({ find: Optional.some })
			]),
			events: derive$3([
				runOnAttached(function(component, _simulatedEvent) {
					Representing.setValue(component, detail.getInitialValue())
				})
			])
		}
	}
	var DataField = single({
		name: 'DataField',
		factory: factory$3,
		configFields: [
			required$1('uid'),
			required$1('dom'),
			required$1('getInitialValue'),
			SketchBehaviours.field('dataBehaviours', [Representing, Composing])
		]
	})

	var get$2 = function(element) {
		return element.dom.value
	}
	var set$2 = function(element, value) {
		if (value === undefined) {
			throw new Error('Value.set was undefined')
		}
		element.dom.value = value
	}

	var schema$8 = constant$1([
		option('data'),
		defaulted('inputAttributes', {}),
		defaulted('inputStyles', {}),
		defaulted('tag', 'input'),
		defaulted('inputClasses', []),
		onHandler('onSetValue'),
		defaulted('styles', {}),
		defaulted('eventOrder', {}),
		field$1('inputBehaviours', [Representing, Focusing]),
		defaulted('selectOnFocus', true)
	])
	var focusBehaviours = function(detail) {
		return derive$2([
			Focusing.config({
				onFocus: !detail.selectOnFocus
					? noop
					: function(component) {
							var input = component.element
							var value = get$2(input)
							input.dom.setSelectionRange(0, value.length)
					  }
			})
		])
	}
	var behaviours = function(detail) {
		return __assign(
			__assign({}, focusBehaviours(detail)),
			augment(detail.inputBehaviours, [
				Representing.config({
					store: __assign(
						__assign(
							{ mode: 'manual' },
							detail.data
								.map(function(data) {
									return { initialValue: data }
								})
								.getOr({})
						),
						{
							getValue: function(input) {
								return get$2(input.element)
							},
							setValue: function(input, data) {
								var current = get$2(input.element)
								if (current !== data) {
									set$2(input.element, data)
								}
							}
						}
					),
					onSetValue: detail.onSetValue
				})
			])
		)
	}
	var dom = function(detail) {
		return {
			tag: detail.tag,
			attributes: __assign({ type: 'text' }, detail.inputAttributes),
			styles: detail.inputStyles,
			classes: detail.inputClasses
		}
	}

	var factory$2 = function(detail, _spec) {
		return {
			uid: detail.uid,
			dom: dom(detail),
			components: [],
			behaviours: behaviours(detail),
			eventOrder: detail.eventOrder
		}
	}
	var Input = single({
		name: 'Input',
		configFields: schema$8(),
		factory: factory$2
	})

	var exhibit$2 = function(base, tabConfig) {
		return nu$3({
			attributes: wrapAll([
				{
					key: tabConfig.tabAttr,
					value: 'true'
				}
			])
		})
	}

	var ActiveTabstopping = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		exhibit: exhibit$2
	})

	var TabstopSchema = [defaulted('tabAttr', 'data-alloy-tabstop')]

	var Tabstopping = create$5({
		fields: TabstopSchema,
		name: 'tabstopping',
		active: ActiveTabstopping
	})

	var global$3 = tinymce.util.Tools.resolve('tinymce.util.I18n')

	var clearInputBehaviour = 'input-clearing'
	var field = function(name, placeholder) {
		var inputSpec = record(
			Input.sketch({
				inputAttributes: { placeholder: global$3.translate(placeholder) },
				onSetValue: function(input, _data) {
					emit(input, input$1())
				},
				inputBehaviours: derive$2([
					Composing.config({ find: Optional.some }),
					Tabstopping.config({}),
					Keying.config({ mode: 'execution' })
				]),
				selectOnFocus: false
			})
		)
		var buttonSpec = record(
			Button.sketch({
				dom: dom$1(
					'<button class="${prefix}-input-container-x ${prefix}-icon-cancel-circle ${prefix}-icon"></button>'
				),
				action: function(button) {
					var input = inputSpec.get(button)
					Representing.setValue(input, '')
				}
			})
		)
		return {
			name: name,
			spec: Container.sketch({
				dom: dom$1('<div class="${prefix}-input-container"></div>'),
				components: [inputSpec.asSpec(), buttonSpec.asSpec()],
				containerBehaviours: derive$2([
					Toggling.config({ toggleClass: resolve('input-container-empty') }),
					Composing.config({
						find: function(comp) {
							return Optional.some(inputSpec.get(comp))
						}
					}),
					config(clearInputBehaviour, [
						run(input$1(), function(iContainer) {
							var input = inputSpec.get(iContainer)
							var val = Representing.getValue(input)
							var f = val.length > 0 ? Toggling.off : Toggling.on
							f(iContainer)
						})
					])
				])
			})
		}
	}
	var hidden = function(name) {
		return {
			name: name,
			spec: DataField.sketch({
				dom: {
					tag: 'span',
					styles: { display: 'none' }
				},
				getInitialValue: function() {
					return Optional.none()
				}
			})
		}
	}

	var nativeDisabled = ['input', 'button', 'textarea', 'select']
	var onLoad = function(component, disableConfig, disableState) {
		var f = disableConfig.disabled() ? disable : enable
		f(component, disableConfig)
	}
	var hasNative = function(component, config) {
		return config.useNative === true && contains$1(nativeDisabled, name$1(component.element))
	}
	var nativeIsDisabled = function(component) {
		return has$1(component.element, 'disabled')
	}
	var nativeDisable = function(component) {
		set$8(component.element, 'disabled', 'disabled')
	}
	var nativeEnable = function(component) {
		remove$6(component.element, 'disabled')
	}
	var ariaIsDisabled = function(component) {
		return get$b(component.element, 'aria-disabled') === 'true'
	}
	var ariaDisable = function(component) {
		set$8(component.element, 'aria-disabled', 'true')
	}
	var ariaEnable = function(component) {
		set$8(component.element, 'aria-disabled', 'false')
	}
	var disable = function(component, disableConfig, _disableState) {
		disableConfig.disableClass.each(function(disableClass) {
			add$1(component.element, disableClass)
		})
		var f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable
		f(component)
		disableConfig.onDisabled(component)
	}
	var enable = function(component, disableConfig, _disableState) {
		disableConfig.disableClass.each(function(disableClass) {
			remove$3(component.element, disableClass)
		})
		var f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable
		f(component)
		disableConfig.onEnabled(component)
	}
	var isDisabled = function(component, disableConfig) {
		return hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component)
	}
	var set$1 = function(component, disableConfig, disableState, disabled) {
		var f = disabled ? disable : enable
		f(component, disableConfig)
	}

	var DisableApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		enable: enable,
		disable: disable,
		isDisabled: isDisabled,
		onLoad: onLoad,
		set: set$1
	})

	var exhibit$1 = function(base, disableConfig) {
		return nu$3({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] })
	}
	var events$3 = function(disableConfig, disableState) {
		return derive$3([
			abort(execute$5(), function(component, _simulatedEvent) {
				return isDisabled(component, disableConfig)
			}),
			loadEvent(disableConfig, disableState, onLoad)
		])
	}

	var ActiveDisable = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		exhibit: exhibit$1,
		events: events$3
	})

	var DisableSchema = [
		defaultedFunction('disabled', never),
		defaulted('useNative', true),
		option('disableClass'),
		onHandler('onDisabled'),
		onHandler('onEnabled')
	]

	var Disabling = create$5({
		fields: DisableSchema,
		name: 'disabling',
		active: ActiveDisable,
		apis: DisableApis
	})

	var owner$1 = 'form'
	var schema$7 = [field$1('formBehaviours', [Representing])]
	var getPartName = function(name) {
		return '<alloy.field.' + name + '>'
	}
	var sketch$4 = function(fSpec) {
		var parts = (function() {
			var record = []
			var field = function(name, config) {
				record.push(name)
				return generateOne(owner$1, getPartName(name), config)
			}
			return {
				field: field,
				record: constant$1(record)
			}
		})()
		var spec = fSpec(parts)
		var partNames = parts.record()
		var fieldParts = map$2(partNames, function(n) {
			return required({
				name: n,
				pname: getPartName(n)
			})
		})
		return composite$1(owner$1, schema$7, fieldParts, make$4, spec)
	}
	var toResult = function(o, e) {
		return o.fold(function() {
			return Result.error(e)
		}, Result.value)
	}
	var make$4 = function(detail, components) {
		return {
			uid: detail.uid,
			dom: detail.dom,
			components: components,
			behaviours: augment(detail.formBehaviours, [
				Representing.config({
					store: {
						mode: 'manual',
						getValue: function(form) {
							var resPs = getAllParts(form, detail)
							return map$1(resPs, function(resPThunk, pName) {
								return resPThunk()
									.bind(function(v) {
										var opt = Composing.getCurrent(v)
										return toResult(
											opt,
											new Error(
												"Cannot find a current component to extract the value from for form part '" +
													pName +
													"': " +
													element(v.element)
											)
										)
									})
									.map(Representing.getValue)
							})
						},
						setValue: function(form, values) {
							each(values, function(newValue, key) {
								getPart(form, detail, key).each(function(wrapper) {
									Composing.getCurrent(wrapper).each(function(field) {
										Representing.setValue(field, newValue)
									})
								})
							})
						}
					}
				})
			]),
			apis: {
				getField: function(form, key) {
					return getPart(form, detail, key).bind(Composing.getCurrent)
				}
			}
		}
	}
	var Form = {
		getField: makeApi(function(apis, component, key) {
			return apis.getField(component, key)
		}),
		sketch: sketch$4
	}

	var SWIPING_LEFT = 1
	var SWIPING_RIGHT = -1
	var SWIPING_NONE = 0
	var init$3 = function(xValue) {
		return {
			xValue: xValue,
			points: []
		}
	}
	var move = function(model, xValue) {
		if (xValue === model.xValue) {
			return model
		}
		var currentDirection = xValue - model.xValue > 0 ? SWIPING_LEFT : SWIPING_RIGHT
		var newPoint = {
			direction: currentDirection,
			xValue: xValue
		}
		var priorPoints = (function() {
			if (model.points.length === 0) {
				return []
			} else {
				var prev = model.points[model.points.length - 1]
				return prev.direction === currentDirection
					? model.points.slice(0, model.points.length - 1)
					: model.points
			}
		})()
		return {
			xValue: xValue,
			points: priorPoints.concat([newPoint])
		}
	}
	var complete = function(model) {
		if (model.points.length === 0) {
			return SWIPING_NONE
		} else {
			var firstDirection = model.points[0].direction
			var lastDirection = model.points[model.points.length - 1].direction
			return firstDirection === SWIPING_RIGHT && lastDirection === SWIPING_RIGHT
				? SWIPING_RIGHT
				: firstDirection === SWIPING_LEFT && lastDirection === SWIPING_LEFT
				? SWIPING_LEFT
				: SWIPING_NONE
		}
	}

	var sketch$3 = function(rawSpec) {
		var navigateEvent = 'navigateEvent'
		var wrapperAdhocEvents = 'serializer-wrapper-events'
		var formAdhocEvents = 'form-events'
		var schema = objOf([
			required$1('fields'),
			defaulted('maxFieldIndex', rawSpec.fields.length - 1),
			required$1('onExecute'),
			required$1('getInitialValue'),
			customField('state', function() {
				return {
					dialogSwipeState: value(),
					currentScreen: Cell(0)
				}
			})
		])
		var spec$1 = asRawOrDie$1('SerialisedDialog', schema, rawSpec)
		var navigationButton = function(direction, directionName, enabled) {
			return Button.sketch({
				dom: dom$1('<span class="${prefix}-icon-' + directionName + ' ${prefix}-icon"></span>'),
				action: function(button) {
					emitWith(button, navigateEvent, { direction: direction })
				},
				buttonBehaviours: derive$2([
					Disabling.config({
						disableClass: resolve('toolbar-navigation-disabled'),
						disabled: function() {
							return !enabled
						}
					})
				])
			})
		}
		var reposition = function(dialog, message) {
			descendant(dialog.element, '.' + resolve('serialised-dialog-chain')).each(function(parent) {
				set$5(parent, 'left', -spec$1.state.currentScreen.get() * message.width + 'px')
			})
		}
		var navigate = function(dialog, direction) {
			var screens = descendants(dialog.element, '.' + resolve('serialised-dialog-screen'))
			descendant(dialog.element, '.' + resolve('serialised-dialog-chain')).each(function(parent) {
				if (
					spec$1.state.currentScreen.get() + direction >= 0 &&
					spec$1.state.currentScreen.get() + direction < screens.length
				) {
					getRaw(parent, 'left').each(function(left) {
						var currentLeft = parseInt(left, 10)
						var w = get$5(screens[0])
						set$5(parent, 'left', currentLeft - direction * w + 'px')
					})
					spec$1.state.currentScreen.set(spec$1.state.currentScreen.get() + direction)
				}
			})
		}
		var focusInput = function(dialog) {
			var inputs = descendants(dialog.element, 'input')
			var optInput = Optional.from(inputs[spec$1.state.currentScreen.get()])
			optInput.each(function(input) {
				dialog
					.getSystem()
					.getByDom(input)
					.each(function(inputComp) {
						dispatchFocus(dialog, inputComp.element)
					})
			})
			var dotitems = memDots.get(dialog)
			Highlighting.highlightAt(dotitems, spec$1.state.currentScreen.get())
		}
		var resetState = function() {
			spec$1.state.currentScreen.set(0)
			spec$1.state.dialogSwipeState.clear()
		}
		var memForm = record(
			Form.sketch(function(parts) {
				return {
					dom: dom$1('<div class="${prefix}-serialised-dialog"></div>'),
					components: [
						Container.sketch({
							dom: dom$1(
								'<div class="${prefix}-serialised-dialog-chain" style="left: 0px; position: absolute;"></div>'
							),
							components: map$2(spec$1.fields, function(field, i) {
								return i <= spec$1.maxFieldIndex
									? Container.sketch({
											dom: dom$1('<div class="${prefix}-serialised-dialog-screen"></div>'),
											components: [
												navigationButton(-1, 'previous', i > 0),
												parts.field(field.name, field.spec),
												navigationButton(+1, 'next', i < spec$1.maxFieldIndex)
											]
									  })
									: parts.field(field.name, field.spec)
							})
						})
					],
					formBehaviours: derive$2([
						orientation(function(dialog, message) {
							reposition(dialog, message)
						}),
						Keying.config({
							mode: 'special',
							focusIn: function(dialog, _specialInfo) {
								focusInput(dialog)
							},
							onTab: function(dialog, _specialInfo) {
								navigate(dialog, +1)
								return Optional.some(true)
							},
							onShiftTab: function(dialog, _specialInfo) {
								navigate(dialog, -1)
								return Optional.some(true)
							}
						}),
						config(formAdhocEvents, [
							runOnAttached(function(dialog, _simulatedEvent) {
								resetState()
								var dotitems = memDots.get(dialog)
								Highlighting.highlightFirst(dotitems)
								spec$1.getInitialValue(dialog).each(function(v) {
									Representing.setValue(dialog, v)
								})
							}),
							runOnExecute(spec$1.onExecute),
							run(transitionend(), function(dialog, simulatedEvent) {
								var event = simulatedEvent.event
								if (event.raw.propertyName === 'left') {
									focusInput(dialog)
								}
							}),
							run(navigateEvent, function(dialog, simulatedEvent) {
								var event = simulatedEvent.event
								var direction = event.direction
								navigate(dialog, direction)
							})
						])
					])
				}
			})
		)
		var memDots = record({
			dom: dom$1('<div class="${prefix}-dot-container"></div>'),
			behaviours: derive$2([
				Highlighting.config({
					highlightClass: resolve('dot-active'),
					itemClass: resolve('dot-item')
				})
			]),
			components: bind$3(spec$1.fields, function(_f, i) {
				return i <= spec$1.maxFieldIndex
					? [spec('<div class="${prefix}-dot-item ${prefix}-icon-full-dot ${prefix}-icon"></div>')]
					: []
			})
		})
		return {
			dom: dom$1('<div class="${prefix}-serializer-wrapper"></div>'),
			components: [memForm.asSpec(), memDots.asSpec()],
			behaviours: derive$2([
				Keying.config({
					mode: 'special',
					focusIn: function(wrapper) {
						var form = memForm.get(wrapper)
						Keying.focusIn(form)
					}
				}),
				config(wrapperAdhocEvents, [
					run(touchstart(), function(_wrapper, simulatedEvent) {
						var event = simulatedEvent.event
						spec$1.state.dialogSwipeState.set(init$3(event.raw.touches[0].clientX))
					}),
					run(touchmove(), function(_wrapper, simulatedEvent) {
						var event = simulatedEvent.event
						spec$1.state.dialogSwipeState.on(function(state) {
							simulatedEvent.event.prevent()
							spec$1.state.dialogSwipeState.set(move(state, event.raw.touches[0].clientX))
						})
					}),
					run(touchend(), function(wrapper, _simulatedEvent) {
						spec$1.state.dialogSwipeState.on(function(state) {
							var dialog = memForm.get(wrapper)
							var direction = -1 * complete(state)
							navigate(dialog, direction)
						})
					})
				])
			])
		}
	}

	var getGroups = cached(function(realm, editor) {
		return [
			{
				label: 'the link group',
				items: [
					sketch$3({
						fields: [
							field('url', 'Type or paste URL'),
							field('text', 'Link text'),
							field('title', 'Link title'),
							field('target', 'Link target'),
							hidden('link')
						],
						maxFieldIndex: ['url', 'text', 'title', 'target'].length - 1,
						getInitialValue: function() {
							return Optional.some(getInfo(editor))
						},
						onExecute: function(dialog, _simulatedEvent) {
							var info = Representing.getValue(dialog)
							applyInfo(editor, info)
							realm.restoreToolbar()
							editor.focus()
						}
					})
				]
			}
		]
	})
	var sketch$2 = function(realm, editor) {
		return forToolbarStateAction(editor, 'link', 'link', function() {
			var groups = getGroups(realm, editor)
			realm.setContextToolbar(groups)
			forAndroid(editor, function() {
				realm.focusToolbar()
			})
			query(editor).each(function(link) {
				editor.selection.select(link.dom)
			})
		})
	}

	var isRecursive = function(component, originator, target) {
		return eq(originator, component.element) && !eq(originator, target)
	}
	var events$2 = derive$3([
		can(focus$4(), function(component, simulatedEvent) {
			var event = simulatedEvent.event
			var originator = event.originator
			var target = event.target
			if (isRecursive(component, originator, target)) {
				console.warn(
					focus$4() +
						' did not get interpreted by the desired target. ' +
						'\nOriginator: ' +
						element(originator) +
						'\nTarget: ' +
						element(target) +
						'\nCheck the ' +
						focus$4() +
						' event handlers'
				)
				return false
			} else {
				return true
			}
		})
	])

	var DefaultEvents = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		events: events$2
	})

	var make$3 = identity

	var NoContextApi = function(getComp) {
		var getMessage = function(event) {
			return (
				'The component must be in a context to execute: ' +
				event +
				(getComp ? '\n' + element(getComp().element) + ' is not in context.' : '')
			)
		}
		var fail = function(event) {
			return function() {
				throw new Error(getMessage(event))
			}
		}
		var warn = function(event) {
			return function() {
				console.warn(getMessage(event))
			}
		}
		return {
			debugInfo: constant$1('fake'),
			triggerEvent: warn('triggerEvent'),
			triggerFocus: warn('triggerFocus'),
			triggerEscape: warn('triggerEscape'),
			broadcast: warn('broadcast'),
			broadcastOn: warn('broadcastOn'),
			broadcastEvent: warn('broadcastEvent'),
			build: fail('build'),
			addToWorld: fail('addToWorld'),
			removeFromWorld: fail('removeFromWorld'),
			addToGui: fail('addToGui'),
			removeFromGui: fail('removeFromGui'),
			getByUid: fail('getByUid'),
			getByDom: fail('getByDom'),
			isConnected: never
		}
	}
	var singleton = NoContextApi()

	var generateFrom$1 = function(spec, all) {
		var schema = map$2(all, function(a) {
			return optionObjOf(a.name(), [required$1('config'), defaulted('state', NoState)])
		})
		var validated = asRaw('component.behaviours', objOf(schema), spec.behaviours).fold(function(errInfo) {
			throw new Error(formatError(errInfo) + '\nComplete spec:\n' + JSON.stringify(spec, null, 2))
		}, identity)
		return {
			list: all,
			data: map$1(validated, function(optBlobThunk) {
				var output = optBlobThunk.map(function(blob) {
					return {
						config: blob.config,
						state: blob.state.init(blob.config)
					}
				})
				return constant$1(output)
			})
		}
	}
	var getBehaviours$1 = function(bData) {
		return bData.list
	}
	var getData = function(bData) {
		return bData.data
	}

	var byInnerKey = function(data, tuple) {
		var r = {}
		each(data, function(detail, key) {
			each(detail, function(value, indexKey) {
				var chain = get$c(r, indexKey).getOr([])
				r[indexKey] = chain.concat([tuple(key, value)])
			})
		})
		return r
	}

	var combine$1 = function(info, baseMod, behaviours, base) {
		var modsByBehaviour = __assign({}, baseMod)
		each$1(behaviours, function(behaviour) {
			modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base)
		})
		var byAspect = byInnerKey(modsByBehaviour, function(name, modification) {
			return {
				name: name,
				modification: modification
			}
		})
		var combineObjects = function(objects) {
			return foldr(
				objects,
				function(b, a) {
					return __assign(__assign({}, a.modification), b)
				},
				{}
			)
		}
		var combinedClasses = foldr(
			byAspect.classes,
			function(b, a) {
				return a.modification.concat(b)
			},
			[]
		)
		var combinedAttributes = combineObjects(byAspect.attributes)
		var combinedStyles = combineObjects(byAspect.styles)
		return nu$3({
			classes: combinedClasses,
			attributes: combinedAttributes,
			styles: combinedStyles
		})
	}

	var sortKeys = function(label, keyName, array, order) {
		try {
			var sorted = sort(array, function(a, b) {
				var aKey = a[keyName]
				var bKey = b[keyName]
				var aIndex = order.indexOf(aKey)
				var bIndex = order.indexOf(bKey)
				if (aIndex === -1) {
					throw new Error(
						'The ordering for ' +
							label +
							' does not have an entry for ' +
							aKey +
							'.\nOrder specified: ' +
							JSON.stringify(order, null, 2)
					)
				}
				if (bIndex === -1) {
					throw new Error(
						'The ordering for ' +
							label +
							' does not have an entry for ' +
							bKey +
							'.\nOrder specified: ' +
							JSON.stringify(order, null, 2)
					)
				}
				if (aIndex < bIndex) {
					return -1
				} else if (bIndex < aIndex) {
					return 1
				} else {
					return 0
				}
			})
			return Result.value(sorted)
		} catch (err) {
			return Result.error([err])
		}
	}

	var uncurried = function(handler, purpose) {
		return {
			handler: handler,
			purpose: purpose
		}
	}
	var curried = function(handler, purpose) {
		return {
			cHandler: handler,
			purpose: purpose
		}
	}
	var curryArgs = function(descHandler, extraArgs) {
		return curried(curry.apply(undefined, [descHandler.handler].concat(extraArgs)), descHandler.purpose)
	}
	var getCurried = function(descHandler) {
		return descHandler.cHandler
	}

	var behaviourTuple = function(name, handler) {
		return {
			name: name,
			handler: handler
		}
	}
	var nameToHandlers = function(behaviours, info) {
		var r = {}
		each$1(behaviours, function(behaviour) {
			r[behaviour.name()] = behaviour.handlers(info)
		})
		return r
	}
	var groupByEvents = function(info, behaviours, base) {
		var behaviourEvents = __assign(__assign({}, base), nameToHandlers(behaviours, info))
		return byInnerKey(behaviourEvents, behaviourTuple)
	}
	var combine = function(info, eventOrder, behaviours, base) {
		var byEventName = groupByEvents(info, behaviours, base)
		return combineGroups(byEventName, eventOrder)
	}
	var assemble = function(rawHandler) {
		var handler = read$1(rawHandler)
		return function(component, simulatedEvent) {
			var rest = []
			for (var _i = 2; _i < arguments.length; _i++) {
				rest[_i - 2] = arguments[_i]
			}
			var args = [component, simulatedEvent].concat(rest)
			if (handler.abort.apply(undefined, args)) {
				simulatedEvent.stop()
			} else if (handler.can.apply(undefined, args)) {
				handler.run.apply(undefined, args)
			}
		}
	}
	var missingOrderError = function(eventName, tuples) {
		return Result.error([
			'The event (' +
				eventName +
				') has more than one behaviour that listens to it.\nWhen this occurs, you must ' +
				'specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that ' +
				'can trigger it are: ' +
				JSON.stringify(
					map$2(tuples, function(c) {
						return c.name
					}),
					null,
					2
				)
		])
	}
	var fuse = function(tuples, eventOrder, eventName) {
		var order = eventOrder[eventName]
		if (!order) {
			return missingOrderError(eventName, tuples)
		} else {
			return sortKeys('Event: ' + eventName, 'name', tuples, order).map(function(sortedTuples) {
				var handlers = map$2(sortedTuples, function(tuple) {
					return tuple.handler
				})
				return fuse$1(handlers)
			})
		}
	}
	var combineGroups = function(byEventName, eventOrder) {
		var r = mapToArray(byEventName, function(tuples, eventName) {
			var combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName)
			return combined.map(function(handler) {
				var assembled = assemble(handler)
				var purpose =
					tuples.length > 1
						? filter$2(eventOrder[eventName], function(o) {
								return exists(tuples, function(t) {
									return t.name === o
								})
						  }).join(' > ')
						: tuples[0].name
				return wrap(eventName, uncurried(assembled, purpose))
			})
		})
		return consolidate(r, {})
	}

	var _a
	var baseBehaviour = 'alloy.base.behaviour'
	var schema$6 = objOf([
		field$2(
			'dom',
			'dom',
			required$2(),
			objOf([
				required$1('tag'),
				defaulted('styles', {}),
				defaulted('classes', []),
				defaulted('attributes', {}),
				option('value'),
				option('innerHtml')
			])
		),
		required$1('components'),
		required$1('uid'),
		defaulted('events', {}),
		defaulted('apis', {}),
		field$2(
			'eventOrder',
			'eventOrder',
			mergeWith(
				((_a = {}),
				(_a[execute$5()] = ['disabling', baseBehaviour, 'toggling', 'typeaheadevents']),
				(_a[focus$4()] = [baseBehaviour, 'focusing', 'keying']),
				(_a[systemInit()] = [baseBehaviour, 'disabling', 'toggling', 'representing']),
				(_a[input$1()] = [baseBehaviour, 'representing', 'streaming', 'invalidating']),
				(_a[detachedFromDom()] = [baseBehaviour, 'representing', 'item-events', 'tooltipping']),
				(_a[mousedown()] = ['focusing', baseBehaviour, 'item-type-events']),
				(_a[touchstart()] = ['focusing', baseBehaviour, 'item-type-events']),
				(_a[mouseover()] = ['item-type-events', 'tooltipping']),
				(_a[receive$1()] = ['receiving', 'reflecting', 'tooltipping']),
				_a)
			),
			anyValue()
		),
		option('domModification')
	])
	var toInfo = function(spec) {
		return asRaw('custom.definition', schema$6, spec)
	}
	var toDefinition = function(detail) {
		return __assign(__assign({}, detail.dom), {
			uid: detail.uid,
			domChildren: map$2(detail.components, function(comp) {
				return comp.element
			})
		})
	}
	var toModification = function(detail) {
		return detail.domModification.fold(function() {
			return nu$3({})
		}, nu$3)
	}
	var toEvents = function(info) {
		return info.events
	}

	var add = function(element, classes) {
		each$1(classes, function(x) {
			add$1(element, x)
		})
	}
	var remove$1 = function(element, classes) {
		each$1(classes, function(x) {
			remove$3(element, x)
		})
	}

	var renderToDom = function(definition) {
		var subject = SugarElement.fromTag(definition.tag)
		setAll$1(subject, definition.attributes)
		add(subject, definition.classes)
		setAll(subject, definition.styles)
		definition.innerHtml.each(function(html) {
			return set$7(subject, html)
		})
		var children = definition.domChildren
		append$1(subject, children)
		definition.value.each(function(value) {
			set$2(subject, value)
		})
		if (!definition.uid) {
		}
		writeOnly(subject, definition.uid)
		return subject
	}

	var getBehaviours = function(spec) {
		var behaviours = get$c(spec, 'behaviours').getOr({})
		return bind$3(keys(behaviours), function(name) {
			var behaviour = behaviours[name]
			return isNonNullable(behaviour) ? [behaviour.me] : []
		})
	}
	var generateFrom = function(spec, all) {
		return generateFrom$1(spec, all)
	}
	var generate$1 = function(spec) {
		var all = getBehaviours(spec)
		return generateFrom(spec, all)
	}

	var getDomDefinition = function(info, bList, bData) {
		var definition = toDefinition(info)
		var infoModification = toModification(info)
		var baseModification = { 'alloy.base.modification': infoModification }
		var modification = bList.length > 0 ? combine$1(bData, baseModification, bList, definition) : infoModification
		return merge(definition, modification)
	}
	var getEvents = function(info, bList, bData) {
		var baseEvents = { 'alloy.base.behaviour': toEvents(info) }
		return combine(bData, info.eventOrder, bList, baseEvents).getOrDie()
	}
	var build$2 = function(spec) {
		var getMe = function() {
			return me
		}
		var systemApi = Cell(singleton)
		var info = getOrDie(toInfo(spec))
		var bBlob = generate$1(spec)
		var bList = getBehaviours$1(bBlob)
		var bData = getData(bBlob)
		var modDefinition = getDomDefinition(info, bList, bData)
		var item = renderToDom(modDefinition)
		var events = getEvents(info, bList, bData)
		var subcomponents = Cell(info.components)
		var connect = function(newApi) {
			systemApi.set(newApi)
		}
		var disconnect = function() {
			systemApi.set(NoContextApi(getMe))
		}
		var syncComponents = function() {
			var children$1 = children(item)
			var subs = bind$3(children$1, function(child) {
				return systemApi
					.get()
					.getByDom(child)
					.fold(function() {
						return []
					}, pure$2)
			})
			subcomponents.set(subs)
		}
		var config = function(behaviour) {
			var b = bData
			var f = isFunction(b[behaviour.name()])
				? b[behaviour.name()]
				: function() {
						throw new Error('Could not find ' + behaviour.name() + ' in ' + JSON.stringify(spec, null, 2))
				  }
			return f()
		}
		var hasConfigured = function(behaviour) {
			return isFunction(bData[behaviour.name()])
		}
		var getApis = function() {
			return info.apis
		}
		var readState = function(behaviourName) {
			return bData[behaviourName]()
				.map(function(b) {
					return b.state.readState()
				})
				.getOr('not enabled')
		}
		var me = {
			uid: spec.uid,
			getSystem: systemApi.get,
			config: config,
			hasConfigured: hasConfigured,
			spec: spec,
			readState: readState,
			getApis: getApis,
			connect: connect,
			disconnect: disconnect,
			element: item,
			syncComponents: syncComponents,
			components: subcomponents.get,
			events: events
		}
		return me
	}

	var buildSubcomponents = function(spec) {
		var components = get$c(spec, 'components').getOr([])
		return map$2(components, build$1)
	}
	var buildFromSpec = function(userSpec) {
		var _a = make$3(userSpec),
			specEvents = _a.events,
			spec = __rest(_a, ['events'])
		var components = buildSubcomponents(spec)
		var completeSpec = __assign(__assign({}, spec), {
			events: __assign(__assign({}, DefaultEvents), specEvents),
			components: components
		})
		return Result.value(build$2(completeSpec))
	}
	var text = function(textContent) {
		var element = SugarElement.fromText(textContent)
		return external({ element: element })
	}
	var external = function(spec) {
		var extSpec = asRawOrDie$1('external.component', objOfOnly([required$1('element'), option('uid')]), spec)
		var systemApi = Cell(NoContextApi())
		var connect = function(newApi) {
			systemApi.set(newApi)
		}
		var disconnect = function() {
			systemApi.set(
				NoContextApi(function() {
					return me
				})
			)
		}
		var uid = extSpec.uid.getOrThunk(function() {
			return generate$2('external')
		})
		writeOnly(extSpec.element, uid)
		var me = {
			uid: uid,
			getSystem: systemApi.get,
			config: Optional.none,
			hasConfigured: never,
			connect: connect,
			disconnect: disconnect,
			getApis: function() {
				return {}
			},
			element: extSpec.element,
			spec: spec,
			readState: constant$1('No state'),
			syncComponents: noop,
			components: constant$1([]),
			events: {}
		}
		return premade$1(me)
	}
	var uids = generate$2
	var isSketchSpec = function(spec) {
		return has$2(spec, 'uid')
	}
	var build$1 = function(spec) {
		return getPremade(spec).getOrThunk(function() {
			var userSpecWithUid = isSketchSpec(spec) ? spec : __assign({ uid: uids('') }, spec)
			return buildFromSpec(userSpecWithUid).getOrDie()
		})
	}
	var premade = premade$1

	var hoverEvent = 'alloy.item-hover'
	var focusEvent = 'alloy.item-focus'
	var onHover = function(item) {
		if (search(item.element).isNone() || Focusing.isFocused(item)) {
			if (!Focusing.isFocused(item)) {
				Focusing.focus(item)
			}
			emitWith(item, hoverEvent, { item: item })
		}
	}
	var onFocus = function(item) {
		emitWith(item, focusEvent, { item: item })
	}
	var hover = constant$1(hoverEvent)
	var focus$1 = constant$1(focusEvent)

	var builder$2 = function(detail) {
		return {
			dom: detail.dom,
			domModification: __assign(__assign({}, detail.domModification), {
				attributes: __assign(
					__assign(
						__assign(
							{ role: detail.toggling.isSome() ? 'menuitemcheckbox' : 'menuitem' },
							detail.domModification.attributes
						),
						{ 'aria-haspopup': detail.hasSubmenu }
					),
					detail.hasSubmenu ? { 'aria-expanded': false } : {}
				)
			}),
			behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
				detail.toggling.fold(Toggling.revoke, function(tConfig) {
					return Toggling.config(__assign({ aria: { mode: 'checked' } }, tConfig))
				}),
				Focusing.config({
					ignore: detail.ignoreFocus,
					stopMousedown: detail.ignoreFocus,
					onFocus: function(component) {
						onFocus(component)
					}
				}),
				Keying.config({ mode: 'execution' }),
				Representing.config({
					store: {
						mode: 'memory',
						initialValue: detail.data
					}
				}),
				config(
					'item-type-events',
					__spreadArray(
						__spreadArray([], pointerEvents(), true),
						[run(mouseover(), onHover), run(focusItem(), Focusing.focus)],
						false
					)
				)
			]),
			components: detail.components,
			eventOrder: detail.eventOrder
		}
	}
	var schema$5 = [
		required$1('data'),
		required$1('components'),
		required$1('dom'),
		defaulted('hasSubmenu', false),
		option('toggling'),
		SketchBehaviours.field('itemBehaviours', [Toggling, Focusing, Keying, Representing]),
		defaulted('ignoreFocus', false),
		defaulted('domModification', {}),
		output('builder', builder$2),
		defaulted('eventOrder', {})
	]

	var builder$1 = function(detail) {
		return {
			dom: detail.dom,
			components: detail.components,
			events: derive$3([stopper(focusItem())])
		}
	}
	var schema$4 = [required$1('dom'), required$1('components'), output('builder', builder$1)]

	var owner = constant$1('item-widget')
	var parts$3 = constant$1([
		required({
			name: 'widget',
			overrides: function(detail) {
				return {
					behaviours: derive$2([
						Representing.config({
							store: {
								mode: 'manual',
								getValue: function(_component) {
									return detail.data
								},
								setValue: noop
							}
						})
					])
				}
			}
		})
	])

	var builder = function(detail) {
		var subs = substitutes(owner(), detail, parts$3())
		var components$1 = components(owner(), detail, subs.internals())
		var focusWidget = function(component) {
			return getPart(component, detail, 'widget').map(function(widget) {
				Keying.focusIn(widget)
				return widget
			})
		}
		var onHorizontalArrow = function(component, simulatedEvent) {
			return inside(simulatedEvent.event.target)
				? Optional.none()
				: (function() {
						if (detail.autofocus) {
							simulatedEvent.setSource(component.element)
							return Optional.none()
						} else {
							return Optional.none()
						}
				  })()
		}
		return {
			dom: detail.dom,
			components: components$1,
			domModification: detail.domModification,
			events: derive$3([
				runOnExecute(function(component, simulatedEvent) {
					focusWidget(component).each(function(_widget) {
						simulatedEvent.stop()
					})
				}),
				run(mouseover(), onHover),
				run(focusItem(), function(component, _simulatedEvent) {
					if (detail.autofocus) {
						focusWidget(component)
					} else {
						Focusing.focus(component)
					}
				})
			]),
			behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
				Representing.config({
					store: {
						mode: 'memory',
						initialValue: detail.data
					}
				}),
				Focusing.config({
					ignore: detail.ignoreFocus,
					onFocus: function(component) {
						onFocus(component)
					}
				}),
				Keying.config({
					mode: 'special',
					focusIn: detail.autofocus
						? function(component) {
								focusWidget(component)
						  }
						: revoke(),
					onLeft: onHorizontalArrow,
					onRight: onHorizontalArrow,
					onEscape: function(component, simulatedEvent) {
						if (!Focusing.isFocused(component) && !detail.autofocus) {
							Focusing.focus(component)
							return Optional.some(true)
						} else if (detail.autofocus) {
							simulatedEvent.setSource(component.element)
							return Optional.none()
						} else {
							return Optional.none()
						}
					}
				})
			])
		}
	}
	var schema$3 = [
		required$1('uid'),
		required$1('data'),
		required$1('components'),
		required$1('dom'),
		defaulted('autofocus', false),
		defaulted('ignoreFocus', false),
		SketchBehaviours.field('widgetBehaviours', [Representing, Focusing, Keying]),
		defaulted('domModification', {}),
		defaultUidsSchema(parts$3()),
		output('builder', builder)
	]

	var itemSchema = choose$1('type', {
		widget: schema$3,
		item: schema$5,
		separator: schema$4
	})
	var configureGrid = function(detail, movementInfo) {
		return {
			mode: 'flatgrid',
			selector: '.' + detail.markers.item,
			initSize: {
				numColumns: movementInfo.initSize.numColumns,
				numRows: movementInfo.initSize.numRows
			},
			focusManager: detail.focusManager
		}
	}
	var configureMatrix = function(detail, movementInfo) {
		return {
			mode: 'matrix',
			selectors: {
				row: movementInfo.rowSelector,
				cell: '.' + detail.markers.item
			},
			focusManager: detail.focusManager
		}
	}
	var configureMenu = function(detail, movementInfo) {
		return {
			mode: 'menu',
			selector: '.' + detail.markers.item,
			moveOnTab: movementInfo.moveOnTab,
			focusManager: detail.focusManager
		}
	}
	var parts$2 = constant$1([
		group({
			factory: {
				sketch: function(spec) {
					var itemInfo = asRawOrDie$1('menu.spec item', itemSchema, spec)
					return itemInfo.builder(itemInfo)
				}
			},
			name: 'items',
			unit: 'item',
			defaults: function(detail, u) {
				return has$2(u, 'uid') ? u : __assign(__assign({}, u), { uid: generate$2('item') })
			},
			overrides: function(detail, u) {
				return {
					type: u.type,
					ignoreFocus: detail.fakeFocus,
					domModification: { classes: [detail.markers.item] }
				}
			}
		})
	])
	var schema$2 = constant$1([
		required$1('value'),
		required$1('items'),
		required$1('dom'),
		required$1('components'),
		defaulted('eventOrder', {}),
		field$1('menuBehaviours', [Highlighting, Representing, Composing, Keying]),
		defaultedOf(
			'movement',
			{
				mode: 'menu',
				moveOnTab: true
			},
			choose$1('mode', {
				grid: [initSize(), output('config', configureGrid)],
				matrix: [output('config', configureMatrix), required$1('rowSelector')],
				menu: [defaulted('moveOnTab', true), output('config', configureMenu)]
			})
		),
		itemMarkers(),
		defaulted('fakeFocus', false),
		defaulted('focusManager', dom$2()),
		onHandler('onHighlight')
	])

	var focus = constant$1('alloy.menu-focus')

	var make$2 = function(detail, components, _spec, _externals) {
		return {
			uid: detail.uid,
			dom: detail.dom,
			markers: detail.markers,
			behaviours: augment(detail.menuBehaviours, [
				Highlighting.config({
					highlightClass: detail.markers.selectedItem,
					itemClass: detail.markers.item,
					onHighlight: detail.onHighlight
				}),
				Representing.config({
					store: {
						mode: 'memory',
						initialValue: detail.value
					}
				}),
				Composing.config({ find: Optional.some }),
				Keying.config(detail.movement.config(detail, detail.movement))
			]),
			events: derive$3([
				run(focus$1(), function(menu, simulatedEvent) {
					var event = simulatedEvent.event
					menu.getSystem()
						.getByDom(event.target)
						.each(function(item) {
							Highlighting.highlight(menu, item)
							simulatedEvent.stop()
							emitWith(menu, focus(), {
								menu: menu,
								item: item
							})
						})
				}),
				run(hover(), function(menu, simulatedEvent) {
					var item = simulatedEvent.event.item
					Highlighting.highlight(menu, item)
				})
			]),
			components: components,
			eventOrder: detail.eventOrder,
			domModification: { attributes: { role: 'menu' } }
		}
	}

	var Menu = composite({
		name: 'Menu',
		configFields: schema$2(),
		partFields: parts$2(),
		factory: make$2
	})

	var preserve = function(f, container) {
		var dos = getRootNode(container)
		var refocus = active(dos).bind(function(focused) {
			var hasFocus = function(elem) {
				return eq(focused, elem)
			}
			return hasFocus(container) ? Optional.some(container) : descendant$1(container, hasFocus)
		})
		var result = f(container)
		refocus.each(function(oldFocus) {
			active(dos)
				.filter(function(newFocus) {
					return eq(newFocus, oldFocus)
				})
				.fold(function() {
					focus$3(oldFocus)
				}, noop)
		})
		return result
	}

	var set = function(component, replaceConfig, replaceState, data) {
		preserve(function() {
			var newChildren = map$2(data, component.getSystem().build)
			replaceChildren(component, newChildren)
		}, component.element)
	}
	var insert = function(component, replaceConfig, insertion, childSpec) {
		var child = component.getSystem().build(childSpec)
		attachWith(component, child, insertion)
	}
	var append = function(component, replaceConfig, replaceState, appendee) {
		insert(component, replaceConfig, append$2, appendee)
	}
	var prepend = function(component, replaceConfig, replaceState, prependee) {
		insert(component, replaceConfig, prepend$1, prependee)
	}
	var remove = function(component, replaceConfig, replaceState, removee) {
		var children = contents(component)
		var foundChild = find$2(children, function(child) {
			return eq(removee.element, child.element)
		})
		foundChild.each(detach)
	}
	var contents = function(component, _replaceConfig) {
		return component.components()
	}
	var replaceAt = function(component, replaceConfig, replaceState, replaceeIndex, replacer) {
		var children = contents(component)
		return Optional.from(children[replaceeIndex]).map(function(replacee) {
			remove(component, replaceConfig, replaceState, replacee)
			replacer.each(function(r) {
				insert(
					component,
					replaceConfig,
					function(p, c) {
						appendAt(p, c, replaceeIndex)
					},
					r
				)
			})
			return replacee
		})
	}
	var replaceBy = function(component, replaceConfig, replaceState, replaceePred, replacer) {
		var children = contents(component)
		return findIndex$1(children, replaceePred).bind(function(replaceeIndex) {
			return replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer)
		})
	}

	var ReplaceApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		append: append,
		prepend: prepend,
		remove: remove,
		replaceAt: replaceAt,
		replaceBy: replaceBy,
		set: set,
		contents: contents
	})

	var Replacing = create$5({
		fields: [],
		name: 'replacing',
		apis: ReplaceApis
	})

	var transpose = function(obj) {
		return tupleMap(obj, function(v, k) {
			return {
				k: v,
				v: k
			}
		})
	}
	var trace = function(items, byItem, byMenu, finish) {
		return get$c(byMenu, finish)
			.bind(function(triggerItem) {
				return get$c(items, triggerItem).bind(function(triggerMenu) {
					var rest = trace(items, byItem, byMenu, triggerMenu)
					return Optional.some([triggerMenu].concat(rest))
				})
			})
			.getOr([])
	}
	var generate = function(menus, expansions) {
		var items = {}
		each(menus, function(menuItems, menu) {
			each$1(menuItems, function(item) {
				items[item] = menu
			})
		})
		var byItem = expansions
		var byMenu = transpose(expansions)
		var menuPaths = map$1(byMenu, function(_triggerItem, submenu) {
			return [submenu].concat(trace(items, byItem, byMenu, submenu))
		})
		return map$1(items, function(menu) {
			return get$c(menuPaths, menu).getOr([menu])
		})
	}

	var init$2 = function() {
		var expansions = Cell({})
		var menus = Cell({})
		var paths = Cell({})
		var primary = value()
		var directory = Cell({})
		var clear = function() {
			expansions.set({})
			menus.set({})
			paths.set({})
			primary.clear()
		}
		var isClear = function() {
			return primary.get().isNone()
		}
		var setMenuBuilt = function(menuName, built) {
			var _a
			menus.set(
				__assign(
					__assign({}, menus.get()),
					((_a = {}),
					(_a[menuName] = {
						type: 'prepared',
						menu: built
					}),
					_a)
				)
			)
		}
		var setContents = function(sPrimary, sMenus, sExpansions, dir) {
			primary.set(sPrimary)
			expansions.set(sExpansions)
			menus.set(sMenus)
			directory.set(dir)
			var sPaths = generate(dir, sExpansions)
			paths.set(sPaths)
		}
		var getTriggeringItem = function(menuValue) {
			return find(expansions.get(), function(v, _k) {
				return v === menuValue
			})
		}
		var getTriggerData = function(menuValue, getItemByValue, path) {
			return getPreparedMenu(menuValue).bind(function(menu) {
				return getTriggeringItem(menuValue).bind(function(triggeringItemValue) {
					return getItemByValue(triggeringItemValue).map(function(triggeredItem) {
						return {
							triggeredMenu: menu,
							triggeringItem: triggeredItem,
							triggeringPath: path
						}
					})
				})
			})
		}
		var getTriggeringPath = function(itemValue, getItemByValue) {
			var extraPath = filter$2(lookupItem(itemValue).toArray(), function(menuValue) {
				return getPreparedMenu(menuValue).isSome()
			})
			return get$c(paths.get(), itemValue).bind(function(path) {
				var revPath = reverse(extraPath.concat(path))
				var triggers = bind$3(revPath, function(menuValue, menuIndex) {
					return getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(
						function() {
							return is(primary.get(), menuValue) ? [] : [Optional.none()]
						},
						function(data) {
							return [Optional.some(data)]
						}
					)
				})
				return sequence(triggers)
			})
		}
		var expand = function(itemValue) {
			return get$c(expansions.get(), itemValue).map(function(menu) {
				var current = get$c(paths.get(), itemValue).getOr([])
				return [menu].concat(current)
			})
		}
		var collapse = function(itemValue) {
			return get$c(paths.get(), itemValue).bind(function(path) {
				return path.length > 1 ? Optional.some(path.slice(1)) : Optional.none()
			})
		}
		var refresh = function(itemValue) {
			return get$c(paths.get(), itemValue)
		}
		var getPreparedMenu = function(menuValue) {
			return lookupMenu(menuValue).bind(extractPreparedMenu)
		}
		var lookupMenu = function(menuValue) {
			return get$c(menus.get(), menuValue)
		}
		var lookupItem = function(itemValue) {
			return get$c(expansions.get(), itemValue)
		}
		var otherMenus = function(path) {
			var menuValues = directory.get()
			return difference(keys(menuValues), path)
		}
		var getPrimary = function() {
			return primary.get().bind(getPreparedMenu)
		}
		var getMenus = function() {
			return menus.get()
		}
		return {
			setMenuBuilt: setMenuBuilt,
			setContents: setContents,
			expand: expand,
			refresh: refresh,
			collapse: collapse,
			lookupMenu: lookupMenu,
			lookupItem: lookupItem,
			otherMenus: otherMenus,
			getPrimary: getPrimary,
			getMenus: getMenus,
			clear: clear,
			isClear: isClear,
			getTriggeringPath: getTriggeringPath
		}
	}
	var extractPreparedMenu = function(prep) {
		return prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none()
	}
	var LayeredState = {
		init: init$2,
		extractPreparedMenu: extractPreparedMenu
	}

	var make$1 = function(detail, _rawUiSpec) {
		var submenuParentItems = value()
		var buildMenus = function(container, primaryName, menus) {
			return map$1(menus, function(spec, name) {
				var makeSketch = function() {
					return Menu.sketch(
						__assign(__assign({}, spec), {
							value: name,
							markers: detail.markers,
							fakeFocus: detail.fakeFocus,
							onHighlight: detail.onHighlight,
							focusManager: detail.fakeFocus ? highlights() : dom$2()
						})
					)
				}
				return name === primaryName
					? {
							type: 'prepared',
							menu: container.getSystem().build(makeSketch())
					  }
					: {
							type: 'notbuilt',
							nbMenu: makeSketch
					  }
			})
		}
		var layeredState = LayeredState.init()
		var setup = function(container) {
			var componentMap = buildMenus(container, detail.data.primary, detail.data.menus)
			var directory = toDirectory()
			layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory)
			return layeredState.getPrimary()
		}
		var getItemValue = function(item) {
			return Representing.getValue(item).value
		}
		var getItemByValue = function(_container, menus, itemValue) {
			return findMap(menus, function(menu) {
				if (!menu.getSystem().isConnected()) {
					return Optional.none()
				}
				var candidates = Highlighting.getCandidates(menu)
				return find$2(candidates, function(c) {
					return getItemValue(c) === itemValue
				})
			})
		}
		var toDirectory = function(_container) {
			return map$1(detail.data.menus, function(data, _menuName) {
				return bind$3(data.items, function(item) {
					return item.type === 'separator' ? [] : [item.data.value]
				})
			})
		}
		var setActiveMenu = function(container, menu) {
			Highlighting.highlight(container, menu)
			Highlighting.getHighlighted(menu)
				.orThunk(function() {
					return Highlighting.getFirst(menu)
				})
				.each(function(item) {
					dispatch(container, item.element, focusItem())
				})
		}
		var getMenus = function(state, menuValues) {
			return cat(
				map$2(menuValues, function(mv) {
					return state.lookupMenu(mv).bind(function(prep) {
						return prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none()
					})
				})
			)
		}
		var closeOthers = function(container, state, path) {
			var others = getMenus(state, state.otherMenus(path))
			each$1(others, function(o) {
				remove$1(o.element, [detail.markers.backgroundMenu])
				if (!detail.stayInDom) {
					Replacing.remove(container, o)
				}
			})
		}
		var getSubmenuParents = function(container) {
			return submenuParentItems.get().getOrThunk(function() {
				var r = {}
				var items = descendants(container.element, '.' + detail.markers.item)
				var parentItems = filter$2(items, function(i) {
					return get$b(i, 'aria-haspopup') === 'true'
				})
				each$1(parentItems, function(i) {
					container
						.getSystem()
						.getByDom(i)
						.each(function(itemComp) {
							var key = getItemValue(itemComp)
							r[key] = itemComp
						})
				})
				submenuParentItems.set(r)
				return r
			})
		}
		var updateAriaExpansions = function(container, path) {
			var parentItems = getSubmenuParents(container)
			each(parentItems, function(v, k) {
				var expanded = contains$1(path, k)
				set$8(v.element, 'aria-expanded', expanded)
			})
		}
		var updateMenuPath = function(container, state, path) {
			return Optional.from(path[0]).bind(function(latestMenuName) {
				return state.lookupMenu(latestMenuName).bind(function(menuPrep) {
					if (menuPrep.type === 'notbuilt') {
						return Optional.none()
					} else {
						var activeMenu = menuPrep.menu
						var rest = getMenus(state, path.slice(1))
						each$1(rest, function(r) {
							add$1(r.element, detail.markers.backgroundMenu)
						})
						if (!inBody(activeMenu.element)) {
							Replacing.append(container, premade(activeMenu))
						}
						remove$1(activeMenu.element, [detail.markers.backgroundMenu])
						setActiveMenu(container, activeMenu)
						closeOthers(container, state, path)
						return Optional.some(activeMenu)
					}
				})
			})
		}
		var ExpandHighlightDecision
		;(function(ExpandHighlightDecision) {
			ExpandHighlightDecision[(ExpandHighlightDecision['HighlightSubmenu'] = 0)] = 'HighlightSubmenu'
			ExpandHighlightDecision[(ExpandHighlightDecision['HighlightParent'] = 1)] = 'HighlightParent'
		})(ExpandHighlightDecision || (ExpandHighlightDecision = {}))
		var buildIfRequired = function(container, menuName, menuPrep) {
			if (menuPrep.type === 'notbuilt') {
				var menu = container.getSystem().build(menuPrep.nbMenu())
				layeredState.setMenuBuilt(menuName, menu)
				return menu
			} else {
				return menuPrep.menu
			}
		}
		var expandRight = function(container, item, decision) {
			if (decision === void 0) {
				decision = ExpandHighlightDecision.HighlightSubmenu
			}
			if (item.hasConfigured(Disabling) && Disabling.isDisabled(item)) {
				return Optional.some(item)
			} else {
				var value = getItemValue(item)
				return layeredState.expand(value).bind(function(path) {
					updateAriaExpansions(container, path)
					return Optional.from(path[0]).bind(function(menuName) {
						return layeredState.lookupMenu(menuName).bind(function(activeMenuPrep) {
							var activeMenu = buildIfRequired(container, menuName, activeMenuPrep)
							if (!inBody(activeMenu.element)) {
								Replacing.append(container, premade(activeMenu))
							}
							detail.onOpenSubmenu(container, item, activeMenu, reverse(path))
							if (decision === ExpandHighlightDecision.HighlightSubmenu) {
								Highlighting.highlightFirst(activeMenu)
								return updateMenuPath(container, layeredState, path)
							} else {
								Highlighting.dehighlightAll(activeMenu)
								return Optional.some(item)
							}
						})
					})
				})
			}
		}
		var collapseLeft = function(container, item) {
			var value = getItemValue(item)
			return layeredState.collapse(value).bind(function(path) {
				updateAriaExpansions(container, path)
				return updateMenuPath(container, layeredState, path).map(function(activeMenu) {
					detail.onCollapseMenu(container, item, activeMenu)
					return activeMenu
				})
			})
		}
		var updateView = function(container, item) {
			var value = getItemValue(item)
			return layeredState.refresh(value).bind(function(path) {
				updateAriaExpansions(container, path)
				return updateMenuPath(container, layeredState, path)
			})
		}
		var onRight = function(container, item) {
			return inside(item.element)
				? Optional.none()
				: expandRight(container, item, ExpandHighlightDecision.HighlightSubmenu)
		}
		var onLeft = function(container, item) {
			return inside(item.element) ? Optional.none() : collapseLeft(container, item)
		}
		var onEscape = function(container, item) {
			return collapseLeft(container, item).orThunk(function() {
				return detail.onEscape(container, item).map(function() {
					return container
				})
			})
		}
		var keyOnItem = function(f) {
			return function(container, simulatedEvent) {
				return closest$1(simulatedEvent.getSource(), '.' + detail.markers.item).bind(function(target) {
					return container
						.getSystem()
						.getByDom(target)
						.toOptional()
						.bind(function(item) {
							return f(container, item).map(always)
						})
				})
			}
		}
		var events = derive$3(
			[
				run(focus(), function(sandbox, simulatedEvent) {
					var item = simulatedEvent.event.item
					layeredState.lookupItem(getItemValue(item)).each(function() {
						var menu = simulatedEvent.event.menu
						Highlighting.highlight(sandbox, menu)
						var value = getItemValue(simulatedEvent.event.item)
						layeredState.refresh(value).each(function(path) {
							return closeOthers(sandbox, layeredState, path)
						})
					})
				}),
				runOnExecute(function(component, simulatedEvent) {
					var target = simulatedEvent.event.target
					component
						.getSystem()
						.getByDom(target)
						.each(function(item) {
							var itemValue = getItemValue(item)
							if (itemValue.indexOf('collapse-item') === 0) {
								collapseLeft(component, item)
							}
							expandRight(component, item, ExpandHighlightDecision.HighlightSubmenu).fold(function() {
								detail.onExecute(component, item)
							}, noop)
						})
				}),
				runOnAttached(function(container, _simulatedEvent) {
					setup(container).each(function(primary) {
						Replacing.append(container, premade(primary))
						detail.onOpenMenu(container, primary)
						if (detail.highlightImmediately) {
							setActiveMenu(container, primary)
						}
					})
				})
			].concat(
				detail.navigateOnHover
					? [
							run(hover(), function(sandbox, simulatedEvent) {
								var item = simulatedEvent.event.item
								updateView(sandbox, item)
								expandRight(sandbox, item, ExpandHighlightDecision.HighlightParent)
								detail.onHover(sandbox, item)
							})
					  ]
					: []
			)
		)
		var getActiveItem = function(container) {
			return Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted)
		}
		var collapseMenuApi = function(container) {
			getActiveItem(container).each(function(currentItem) {
				collapseLeft(container, currentItem)
			})
		}
		var highlightPrimary = function(container) {
			layeredState.getPrimary().each(function(primary) {
				setActiveMenu(container, primary)
			})
		}
		var extractMenuFromContainer = function(container) {
			return Optional.from(container.components()[0]).filter(function(comp) {
				return get$b(comp.element, 'role') === 'menu'
			})
		}
		var repositionMenus = function(container) {
			var maybeActivePrimary = layeredState.getPrimary().bind(function(primary) {
				return getActiveItem(container)
					.bind(function(currentItem) {
						var itemValue = getItemValue(currentItem)
						var allMenus = values(layeredState.getMenus())
						var preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu))
						return layeredState.getTriggeringPath(itemValue, function(v) {
							return getItemByValue(container, preparedMenus, v)
						})
					})
					.map(function(triggeringPath) {
						return {
							primary: primary,
							triggeringPath: triggeringPath
						}
					})
			})
			maybeActivePrimary.fold(
				function() {
					extractMenuFromContainer(container).each(function(primaryMenu) {
						detail.onRepositionMenu(container, primaryMenu, [])
					})
				},
				function(_a) {
					var primary = _a.primary,
						triggeringPath = _a.triggeringPath
					detail.onRepositionMenu(container, primary, triggeringPath)
				}
			)
		}
		var apis = {
			collapseMenu: collapseMenuApi,
			highlightPrimary: highlightPrimary,
			repositionMenus: repositionMenus
		}
		return {
			uid: detail.uid,
			dom: detail.dom,
			markers: detail.markers,
			behaviours: augment(detail.tmenuBehaviours, [
				Keying.config({
					mode: 'special',
					onRight: keyOnItem(onRight),
					onLeft: keyOnItem(onLeft),
					onEscape: keyOnItem(onEscape),
					focusIn: function(container, _keyInfo) {
						layeredState.getPrimary().each(function(primary) {
							dispatch(container, primary.element, focusItem())
						})
					}
				}),
				Highlighting.config({
					highlightClass: detail.markers.selectedMenu,
					itemClass: detail.markers.menu
				}),
				Composing.config({
					find: function(container) {
						return Highlighting.getHighlighted(container)
					}
				}),
				Replacing.config({})
			]),
			eventOrder: detail.eventOrder,
			apis: apis,
			events: events
		}
	}
	var collapseItem$1 = constant$1('collapse-item')

	var tieredData = function(primary, menus, expansions) {
		return {
			primary: primary,
			menus: menus,
			expansions: expansions
		}
	}
	var singleData = function(name, menu) {
		return {
			primary: name,
			menus: wrap(name, menu),
			expansions: {}
		}
	}
	var collapseItem = function(text) {
		return {
			value: generate$4(collapseItem$1()),
			meta: { text: text }
		}
	}
	var tieredMenu = single({
		name: 'TieredMenu',
		configFields: [
			onStrictKeyboardHandler('onExecute'),
			onStrictKeyboardHandler('onEscape'),
			onStrictHandler('onOpenMenu'),
			onStrictHandler('onOpenSubmenu'),
			onHandler('onRepositionMenu'),
			onHandler('onCollapseMenu'),
			defaulted('highlightImmediately', true),
			requiredObjOf('data', [required$1('primary'), required$1('menus'), required$1('expansions')]),
			defaulted('fakeFocus', false),
			onHandler('onHighlight'),
			onHandler('onHover'),
			tieredMenuMarkers(),
			required$1('dom'),
			defaulted('navigateOnHover', true),
			defaulted('stayInDom', false),
			field$1('tmenuBehaviours', [Keying, Highlighting, Composing, Replacing]),
			defaulted('eventOrder', {})
		],
		apis: {
			collapseMenu: function(apis, tmenu) {
				apis.collapseMenu(tmenu)
			},
			highlightPrimary: function(apis, tmenu) {
				apis.highlightPrimary(tmenu)
			},
			repositionMenus: function(apis, tmenu) {
				apis.repositionMenus(tmenu)
			}
		},
		factory: make$1,
		extraApis: {
			tieredData: tieredData,
			singleData: singleData,
			collapseItem: collapseItem
		}
	})

	var findRoute = function(component, transConfig, transState, route) {
		return get$c(transConfig.routes, route.start).bind(function(sConfig) {
			return get$c(sConfig, route.destination)
		})
	}
	var getTransition = function(comp, transConfig, transState) {
		var route = getCurrentRoute(comp, transConfig)
		return route.bind(function(r) {
			return getTransitionOf(comp, transConfig, transState, r)
		})
	}
	var getTransitionOf = function(comp, transConfig, transState, route) {
		return findRoute(comp, transConfig, transState, route).bind(function(r) {
			return r.transition.map(function(t) {
				return {
					transition: t,
					route: r
				}
			})
		})
	}
	var disableTransition = function(comp, transConfig, transState) {
		getTransition(comp, transConfig, transState).each(function(routeTransition) {
			var t = routeTransition.transition
			remove$3(comp.element, t.transitionClass)
			remove$6(comp.element, transConfig.destinationAttr)
		})
	}
	var getNewRoute = function(comp, transConfig, transState, destination) {
		return {
			start: get$b(comp.element, transConfig.stateAttr),
			destination: destination
		}
	}
	var getCurrentRoute = function(comp, transConfig, _transState) {
		var el = comp.element
		return getOpt(el, transConfig.destinationAttr).map(function(destination) {
			return {
				start: get$b(comp.element, transConfig.stateAttr),
				destination: destination
			}
		})
	}
	var jumpTo = function(comp, transConfig, transState, destination) {
		disableTransition(comp, transConfig, transState)
		if (has$1(comp.element, transConfig.stateAttr) && get$b(comp.element, transConfig.stateAttr) !== destination) {
			transConfig.onFinish(comp, destination)
		}
		set$8(comp.element, transConfig.stateAttr, destination)
	}
	var fasttrack = function(comp, transConfig, _transState, _destination) {
		if (has$1(comp.element, transConfig.destinationAttr)) {
			getOpt(comp.element, transConfig.destinationAttr).each(function(destination) {
				set$8(comp.element, transConfig.stateAttr, destination)
			})
			remove$6(comp.element, transConfig.destinationAttr)
		}
	}
	var progressTo = function(comp, transConfig, transState, destination) {
		fasttrack(comp, transConfig)
		var route = getNewRoute(comp, transConfig, transState, destination)
		getTransitionOf(comp, transConfig, transState, route).fold(
			function() {
				jumpTo(comp, transConfig, transState, destination)
			},
			function(routeTransition) {
				disableTransition(comp, transConfig, transState)
				var t = routeTransition.transition
				add$1(comp.element, t.transitionClass)
				set$8(comp.element, transConfig.destinationAttr, destination)
			}
		)
	}
	var getState = function(comp, transConfig, _transState) {
		return getOpt(comp.element, transConfig.stateAttr)
	}

	var TransitionApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		findRoute: findRoute,
		disableTransition: disableTransition,
		getCurrentRoute: getCurrentRoute,
		jumpTo: jumpTo,
		progressTo: progressTo,
		getState: getState
	})

	var events$1 = function(transConfig, transState) {
		return derive$3([
			run(transitionend(), function(component, simulatedEvent) {
				var raw = simulatedEvent.event.raw
				getCurrentRoute(component, transConfig).each(function(route) {
					findRoute(component, transConfig, transState, route).each(function(rInfo) {
						rInfo.transition.each(function(rTransition) {
							if (raw.propertyName === rTransition.property) {
								jumpTo(component, transConfig, transState, route.destination)
								transConfig.onTransition(component, route)
							}
						})
					})
				})
			}),
			runOnAttached(function(comp, _se) {
				jumpTo(comp, transConfig, transState, transConfig.initialState)
			})
		])
	}

	var ActiveTransitioning = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		events: events$1
	})

	var TransitionSchema = [
		defaulted('destinationAttr', 'data-transitioning-destination'),
		defaulted('stateAttr', 'data-transitioning-state'),
		required$1('initialState'),
		onHandler('onTransition'),
		onHandler('onFinish'),
		requiredOf(
			'routes',
			setOf(
				Result.value,
				setOf(
					Result.value,
					objOfOnly([optionObjOfOnly('transition', [required$1('property'), required$1('transitionClass')])])
				)
			)
		)
	]

	var createRoutes = function(routes) {
		var r = {}
		each(routes, function(v, k) {
			var waypoints = k.split('<->')
			r[waypoints[0]] = wrap(waypoints[1], v)
			r[waypoints[1]] = wrap(waypoints[0], v)
		})
		return r
	}
	var createBistate = function(first, second, transitions) {
		return wrapAll([
			{
				key: first,
				value: wrap(second, transitions)
			},
			{
				key: second,
				value: wrap(first, transitions)
			}
		])
	}
	var createTristate = function(first, second, third, transitions) {
		return wrapAll([
			{
				key: first,
				value: wrapAll([
					{
						key: second,
						value: transitions
					},
					{
						key: third,
						value: transitions
					}
				])
			},
			{
				key: second,
				value: wrapAll([
					{
						key: first,
						value: transitions
					},
					{
						key: third,
						value: transitions
					}
				])
			},
			{
				key: third,
				value: wrapAll([
					{
						key: first,
						value: transitions
					},
					{
						key: second,
						value: transitions
					}
				])
			}
		])
	}
	var Transitioning = create$5({
		fields: TransitionSchema,
		name: 'transitioning',
		active: ActiveTransitioning,
		apis: TransitionApis,
		extra: {
			createRoutes: createRoutes,
			createBistate: createBistate,
			createTristate: createTristate
		}
	})

	var scrollableStyle = resolve('scrollable')
	var register$2 = function(element) {
		add$1(element, scrollableStyle)
	}
	var deregister = function(element) {
		remove$3(element, scrollableStyle)
	}
	var scrollable = scrollableStyle

	var getValue = function(item) {
		return get$c(item, 'format').getOr(item.title)
	}
	var convert = function(formats, memMenuThunk) {
		var mainMenu = makeMenu(
			'Styles',
			[].concat(
				map$2(formats.items, function(k) {
					return makeItem(
						getValue(k),
						k.title,
						k.isSelected(),
						k.getPreview(),
						hasNonNullableKey(formats.expansions, getValue(k))
					)
				})
			),
			memMenuThunk,
			false
		)
		var submenus = map$1(formats.menus, function(menuItems, menuName) {
			var items = map$2(menuItems, function(item) {
				return makeItem(
					getValue(item),
					item.title,
					item.isSelected !== undefined ? item.isSelected() : false,
					item.getPreview !== undefined ? item.getPreview() : '',
					hasNonNullableKey(formats.expansions, getValue(item))
				)
			})
			return makeMenu(menuName, items, memMenuThunk, true)
		})
		var menus = deepMerge(submenus, wrap('styles', mainMenu))
		var tmenu = tieredMenu.tieredData('styles', menus, formats.expansions)
		return { tmenu: tmenu }
	}
	var makeItem = function(value, text, selected, preview, isMenu) {
		return {
			data: {
				value: value,
				text: text
			},
			type: 'item',
			dom: {
				tag: 'div',
				classes: isMenu ? [resolve('styles-item-is-menu')] : []
			},
			toggling: {
				toggleOnExecute: false,
				toggleClass: resolve('format-matches'),
				selected: selected
			},
			itemBehaviours: derive$2(
				isMenu
					? []
					: [
							format(value, function(comp, status) {
								var toggle = status ? Toggling.on : Toggling.off
								toggle(comp)
							})
					  ]
			),
			components: [
				{
					dom: {
						tag: 'div',
						attributes: { style: preview },
						innerHtml: text
					}
				}
			]
		}
	}
	var makeMenu = function(value, items, memMenuThunk, collapsable) {
		return {
			value: value,
			dom: { tag: 'div' },
			components: [
				Button.sketch({
					dom: {
						tag: 'div',
						classes: [resolve('styles-collapser')]
					},
					components: collapsable
						? [
								{
									dom: {
										tag: 'span',
										classes: [resolve('styles-collapse-icon')]
									}
								},
								text(value)
						  ]
						: [text(value)],
					action: function(item) {
						if (collapsable) {
							var comp = memMenuThunk().get(item)
							tieredMenu.collapseMenu(comp)
						}
					}
				}),
				{
					dom: {
						tag: 'div',
						classes: [resolve('styles-menu-items-container')]
					},
					components: [Menu.parts.items({})],
					behaviours: derive$2([
						config('adhoc-scrollable-menu', [
							runOnAttached(function(component, _simulatedEvent) {
								set$5(component.element, 'overflow-y', 'auto')
								set$5(component.element, '-webkit-overflow-scrolling', 'touch')
								register$2(component.element)
							}),
							runOnDetached(function(component) {
								remove$2(component.element, 'overflow-y')
								remove$2(component.element, '-webkit-overflow-scrolling')
								deregister(component.element)
							})
						])
					])
				}
			],
			items: items,
			menuBehaviours: derive$2([
				Transitioning.config({
					initialState: 'after',
					routes: Transitioning.createTristate('before', 'current', 'after', {
						transition: {
							property: 'transform',
							transitionClass: 'transitioning'
						}
					})
				})
			])
		}
	}
	var sketch$1 = function(settings) {
		var dataset = convert(settings.formats, function() {
			return memMenu
		})
		var memMenu = record(
			tieredMenu.sketch({
				dom: {
					tag: 'div',
					classes: [resolve('styles-menu')]
				},
				components: [],
				fakeFocus: true,
				stayInDom: true,
				onExecute: function(_tmenu, item) {
					var v = Representing.getValue(item)
					settings.handle(item, v.value)
					return Optional.none()
				},
				onEscape: function() {
					return Optional.none()
				},
				onOpenMenu: function(container, menu) {
					var w = get$5(container.element)
					set$4(menu.element, w)
					Transitioning.jumpTo(menu, 'current')
				},
				onOpenSubmenu: function(container, item, submenu) {
					var w = get$5(container.element)
					var menu = ancestor(item.element, '[role="menu"]').getOrDie('hacky')
					var menuComp = container
						.getSystem()
						.getByDom(menu)
						.getOrDie()
					set$4(submenu.element, w)
					Transitioning.progressTo(menuComp, 'before')
					Transitioning.jumpTo(submenu, 'after')
					Transitioning.progressTo(submenu, 'current')
				},
				onCollapseMenu: function(container, item, menu) {
					var submenu = ancestor(item.element, '[role="menu"]').getOrDie('hacky')
					var submenuComp = container
						.getSystem()
						.getByDom(submenu)
						.getOrDie()
					Transitioning.progressTo(submenuComp, 'after')
					Transitioning.progressTo(menu, 'current')
				},
				navigateOnHover: false,
				highlightImmediately: true,
				data: dataset.tmenu,
				markers: {
					backgroundMenu: resolve('styles-background-menu'),
					menu: resolve('styles-menu'),
					selectedMenu: resolve('styles-selected-menu'),
					item: resolve('styles-item'),
					selectedItem: resolve('styles-selected-item')
				}
			})
		)
		return memMenu.asSpec()
	}

	var getFromExpandingItem = function(item) {
		var newItem = deepMerge(exclude(item, ['items']), { menu: true })
		var rest = expand(item.items)
		var newMenus = deepMerge(rest.menus, wrap(item.title, rest.items))
		var newExpansions = deepMerge(rest.expansions, wrap(item.title, item.title))
		return {
			item: newItem,
			menus: newMenus,
			expansions: newExpansions
		}
	}
	var getFromItem = function(item) {
		return hasNonNullableKey(item, 'items')
			? getFromExpandingItem(item)
			: {
					item: item,
					menus: {},
					expansions: {}
			  }
	}
	var expand = function(items) {
		return foldr(
			items,
			function(acc, item) {
				var newData = getFromItem(item)
				return {
					menus: deepMerge(acc.menus, newData.menus),
					items: [newData.item].concat(acc.items),
					expansions: deepMerge(acc.expansions, newData.expansions)
				}
			},
			{
				menus: {},
				expansions: {},
				items: []
			}
		)
	}

	var register$1 = function(editor) {
		var isSelectedFor = function(format) {
			return function() {
				return editor.formatter.match(format)
			}
		}
		var getPreview = function(format) {
			return function() {
				return editor.formatter.getCssText(format)
			}
		}
		var enrichSupported = function(item) {
			return deepMerge(item, {
				isSelected: isSelectedFor(item.format),
				getPreview: getPreview(item.format)
			})
		}
		var enrichMenu = function(item) {
			return deepMerge(item, {
				isSelected: never,
				getPreview: constant$1('')
			})
		}
		var enrichCustom = function(item) {
			var formatName = generate$4(item.title)
			var newItem = deepMerge(item, {
				format: formatName,
				isSelected: isSelectedFor(formatName),
				getPreview: getPreview(formatName)
			})
			editor.formatter.register(formatName, newItem)
			return newItem
		}
		var doEnrich = function(items) {
			return map$2(items, function(item) {
				if (hasNonNullableKey(item, 'items')) {
					var newItems = doEnrich(item.items)
					return deepMerge(enrichMenu(item), { items: newItems })
				} else if (hasNonNullableKey(item, 'format')) {
					return enrichSupported(item)
				} else {
					return enrichCustom(item)
				}
			})
		}
		return doEnrich(getStyleFormats(editor))
	}
	var prune = function(editor, formats) {
		var doPrune = function(items) {
			return bind$3(items, function(item) {
				if (item.items !== undefined) {
					var newItems = doPrune(item.items)
					return newItems.length > 0 ? [item] : []
				} else {
					var keep = hasNonNullableKey(item, 'format') ? editor.formatter.canApply(item.format) : true
					return keep ? [item] : []
				}
			})
		}
		var prunedItems = doPrune(formats)
		return expand(prunedItems)
	}
	var ui = function(editor, formats, onDone) {
		var pruned = prune(editor, formats)
		return sketch$1({
			formats: pruned,
			handle: function(item, value) {
				editor.undoManager.transact(function() {
					if (Toggling.isOn(item)) {
						editor.formatter.remove(value)
					} else {
						editor.formatter.apply(value)
					}
				})
				onDone()
			}
		})
	}

	var extract = function(rawToolbar) {
		var toolbar = rawToolbar.replace(/\|/g, ' ').trim()
		return toolbar.length > 0 ? toolbar.split(/\s+/) : []
	}
	var identifyFromArray = function(toolbar) {
		return bind$3(toolbar, function(item) {
			return isArray(item) ? identifyFromArray(item) : extract(item)
		})
	}
	var identify = function(editor) {
		var toolbar = getToolbar(editor)
		return isArray(toolbar) ? identifyFromArray(toolbar) : extract(toolbar)
	}
	var setup$3 = function(realm, editor) {
		var commandSketch = function(name) {
			return function() {
				return forToolbarCommand(editor, name)
			}
		}
		var stateCommandSketch = function(name) {
			return function() {
				return forToolbarStateCommand(editor, name)
			}
		}
		var actionSketch = function(name, query, action) {
			return function() {
				return forToolbarStateAction(editor, name, query, action)
			}
		}
		var undo = commandSketch('undo')
		var redo = commandSketch('redo')
		var bold = stateCommandSketch('bold')
		var italic = stateCommandSketch('italic')
		var underline = stateCommandSketch('underline')
		var removeformat = commandSketch('removeformat')
		var link = function() {
			return sketch$2(realm, editor)
		}
		var unlink = actionSketch('unlink', 'link', function() {
			editor.execCommand('unlink', null, false)
		})
		var image = function() {
			return sketch$5(editor)
		}
		var bullist = actionSketch('unordered-list', 'ul', function() {
			editor.execCommand('InsertUnorderedList', null, false)
		})
		var numlist = actionSketch('ordered-list', 'ol', function() {
			editor.execCommand('InsertOrderedList', null, false)
		})
		var fontsizeselect = function() {
			return sketch$6(realm, editor)
		}
		var forecolor = function() {
			return sketch$8(realm, editor)
		}
		var styleFormats = register$1(editor)
		var styleFormatsMenu = function() {
			return ui(editor, styleFormats, function() {
				editor.fire('scrollIntoView')
			})
		}
		var styleselect = function() {
			return forToolbar(
				'style-formats',
				function(button) {
					editor.fire('toReading')
					realm.dropup.appear(styleFormatsMenu, Toggling.on, button)
				},
				derive$2([
					Toggling.config({
						toggleClass: resolve('toolbar-button-selected'),
						toggleOnExecute: false,
						aria: { mode: 'pressed' }
					}),
					Receiving.config({
						channels: wrapAll([
							receive(orientationChanged, Toggling.off),
							receive(dropupDismissed, Toggling.off)
						])
					})
				]),
				editor
			)
		}
		var feature = function(prereq, sketch) {
			return {
				isSupported: function() {
					var buttons = editor.ui.registry.getAll().buttons
					return prereq.forall(function(p) {
						return hasNonNullableKey(buttons, p)
					})
				},
				sketch: sketch
			}
		}
		return {
			undo: feature(Optional.none(), undo),
			redo: feature(Optional.none(), redo),
			bold: feature(Optional.none(), bold),
			italic: feature(Optional.none(), italic),
			underline: feature(Optional.none(), underline),
			removeformat: feature(Optional.none(), removeformat),
			link: feature(Optional.none(), link),
			unlink: feature(Optional.none(), unlink),
			image: feature(Optional.none(), image),
			bullist: feature(Optional.some('bullist'), bullist),
			numlist: feature(Optional.some('numlist'), numlist),
			fontsizeselect: feature(Optional.none(), fontsizeselect),
			forecolor: feature(Optional.none(), forecolor),
			styleselect: feature(Optional.none(), styleselect)
		}
	}
	var detect = function(editor, features) {
		var itemNames = identify(editor)
		var present = {}
		return bind$3(itemNames, function(iName) {
			var r =
				!hasNonNullableKey(present, iName) &&
				hasNonNullableKey(features, iName) &&
				features[iName].isSupported()
					? [features[iName].sketch()]
					: []
			present[iName] = true
			return r
		})
	}

	var mkEvent = function(target, x, y, stop, prevent, kill, raw) {
		return {
			target: target,
			x: x,
			y: y,
			stop: stop,
			prevent: prevent,
			kill: kill,
			raw: raw
		}
	}
	var fromRawEvent = function(rawEvent) {
		var target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target))
		var stop = function() {
			return rawEvent.stopPropagation()
		}
		var prevent = function() {
			return rawEvent.preventDefault()
		}
		var kill = compose(prevent, stop)
		return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent)
	}
	var handle = function(filter, handler) {
		return function(rawEvent) {
			if (filter(rawEvent)) {
				handler(fromRawEvent(rawEvent))
			}
		}
	}
	var binder = function(element, event, filter, handler, useCapture) {
		var wrapped = handle(filter, handler)
		element.dom.addEventListener(event, wrapped, useCapture)
		return { unbind: curry(unbind, element, event, wrapped, useCapture) }
	}
	var bind$1 = function(element, event, filter, handler) {
		return binder(element, event, filter, handler, false)
	}
	var capture$1 = function(element, event, filter, handler) {
		return binder(element, event, filter, handler, true)
	}
	var unbind = function(element, event, handler, useCapture) {
		element.dom.removeEventListener(event, handler, useCapture)
	}

	var filter = always
	var bind = function(element, event, handler) {
		return bind$1(element, event, filter, handler)
	}
	var capture = function(element, event, handler) {
		return capture$1(element, event, filter, handler)
	}

	var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay')

	var INTERVAL = 50
	var INSURANCE = 1000 / INTERVAL
	var get$1 = function(outerWindow) {
		var isPortrait = outerWindow.matchMedia('(orientation: portrait)').matches
		return { isPortrait: constant$1(isPortrait) }
	}
	var getActualWidth = function(outerWindow) {
		var isIos = detect$1().os.isiOS()
		var isPortrait = get$1(outerWindow).isPortrait()
		return isIos && !isPortrait ? outerWindow.screen.height : outerWindow.screen.width
	}
	var onChange = function(outerWindow, listeners) {
		var win = SugarElement.fromDom(outerWindow)
		var poller = null
		var change = function() {
			global$2.clearInterval(poller)
			var orientation = get$1(outerWindow)
			listeners.onChange(orientation)
			onAdjustment(function() {
				listeners.onReady(orientation)
			})
		}
		var orientationHandle = bind(win, 'orientationchange', change)
		var onAdjustment = function(f) {
			global$2.clearInterval(poller)
			var flag = outerWindow.innerHeight
			var insurance = 0
			poller = global$2.setInterval(function() {
				if (flag !== outerWindow.innerHeight) {
					global$2.clearInterval(poller)
					f(Optional.some(outerWindow.innerHeight))
				} else if (insurance > INSURANCE) {
					global$2.clearInterval(poller)
					f(Optional.none())
				}
				insurance++
			}, INTERVAL)
		}
		var destroy = function() {
			orientationHandle.unbind()
		}
		return {
			onAdjustment: onAdjustment,
			destroy: destroy
		}
	}

	var setStart = function(rng, situ) {
		situ.fold(
			function(e) {
				rng.setStartBefore(e.dom)
			},
			function(e, o) {
				rng.setStart(e.dom, o)
			},
			function(e) {
				rng.setStartAfter(e.dom)
			}
		)
	}
	var setFinish = function(rng, situ) {
		situ.fold(
			function(e) {
				rng.setEndBefore(e.dom)
			},
			function(e, o) {
				rng.setEnd(e.dom, o)
			},
			function(e) {
				rng.setEndAfter(e.dom)
			}
		)
	}
	var relativeToNative = function(win, startSitu, finishSitu) {
		var range = win.document.createRange()
		setStart(range, startSitu)
		setFinish(range, finishSitu)
		return range
	}
	var exactToNative = function(win, start, soffset, finish, foffset) {
		var rng = win.document.createRange()
		rng.setStart(start.dom, soffset)
		rng.setEnd(finish.dom, foffset)
		return rng
	}
	var toRect$1 = function(rect) {
		return {
			left: rect.left,
			top: rect.top,
			right: rect.right,
			bottom: rect.bottom,
			width: rect.width,
			height: rect.height
		}
	}
	var getFirstRect$1 = function(rng) {
		var rects = rng.getClientRects()
		var rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect()
		return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect$1) : Optional.none()
	}

	var adt$3 = Adt.generate([
		{
			ltr: ['start', 'soffset', 'finish', 'foffset']
		},
		{
			rtl: ['start', 'soffset', 'finish', 'foffset']
		}
	])
	var fromRange = function(win, type, range) {
		return type(
			SugarElement.fromDom(range.startContainer),
			range.startOffset,
			SugarElement.fromDom(range.endContainer),
			range.endOffset
		)
	}
	var getRanges = function(win, selection) {
		return selection.match({
			domRange: function(rng) {
				return {
					ltr: constant$1(rng),
					rtl: Optional.none
				}
			},
			relative: function(startSitu, finishSitu) {
				return {
					ltr: cached(function() {
						return relativeToNative(win, startSitu, finishSitu)
					}),
					rtl: cached(function() {
						return Optional.some(relativeToNative(win, finishSitu, startSitu))
					})
				}
			},
			exact: function(start, soffset, finish, foffset) {
				return {
					ltr: cached(function() {
						return exactToNative(win, start, soffset, finish, foffset)
					}),
					rtl: cached(function() {
						return Optional.some(exactToNative(win, finish, foffset, start, soffset))
					})
				}
			}
		})
	}
	var doDiagnose = function(win, ranges) {
		var rng = ranges.ltr()
		if (rng.collapsed) {
			var reversed = ranges.rtl().filter(function(rev) {
				return rev.collapsed === false
			})
			return reversed
				.map(function(rev) {
					return adt$3.rtl(
						SugarElement.fromDom(rev.endContainer),
						rev.endOffset,
						SugarElement.fromDom(rev.startContainer),
						rev.startOffset
					)
				})
				.getOrThunk(function() {
					return fromRange(win, adt$3.ltr, rng)
				})
		} else {
			return fromRange(win, adt$3.ltr, rng)
		}
	}
	var diagnose = function(win, selection) {
		var ranges = getRanges(win, selection)
		return doDiagnose(win, ranges)
	}
	var asLtrRange = function(win, selection) {
		var diagnosis = diagnose(win, selection)
		return diagnosis.match({
			ltr: function(start, soffset, finish, foffset) {
				var rng = win.document.createRange()
				rng.setStart(start.dom, soffset)
				rng.setEnd(finish.dom, foffset)
				return rng
			},
			rtl: function(start, soffset, finish, foffset) {
				var rng = win.document.createRange()
				rng.setStart(finish.dom, foffset)
				rng.setEnd(start.dom, soffset)
				return rng
			}
		})
	}
	adt$3.ltr
	adt$3.rtl

	var create$3 = function(start, soffset, finish, foffset) {
		return {
			start: start,
			soffset: soffset,
			finish: finish,
			foffset: foffset
		}
	}
	var SimRange = { create: create$3 }

	var NodeValue = function(is, name) {
		var get = function(element) {
			if (!is(element)) {
				throw new Error('Can only get ' + name + ' value of a ' + name + ' node')
			}
			return getOption(element).getOr('')
		}
		var getOption = function(element) {
			return is(element) ? Optional.from(element.dom.nodeValue) : Optional.none()
		}
		var set = function(element, value) {
			if (!is(element)) {
				throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node')
			}
			element.dom.nodeValue = value
		}
		return {
			get: get,
			getOption: getOption,
			set: set
		}
	}

	var api = NodeValue(isText, 'text')
	var getOption = function(element) {
		return api.getOption(element)
	}

	var getEnd = function(element) {
		return name$1(element) === 'img'
			? 1
			: getOption(element).fold(
					function() {
						return children(element).length
					},
					function(v) {
						return v.length
					}
			  )
	}

	var adt$2 = Adt.generate([
		{ before: ['element'] },
		{
			on: ['element', 'offset']
		},
		{ after: ['element'] }
	])
	var cata = function(subject, onBefore, onOn, onAfter) {
		return subject.fold(onBefore, onOn, onAfter)
	}
	var getStart$1 = function(situ) {
		return situ.fold(identity, identity, identity)
	}
	var before = adt$2.before
	var on = adt$2.on
	var after$1 = adt$2.after
	var Situ = {
		before: before,
		on: on,
		after: after$1,
		cata: cata,
		getStart: getStart$1
	}

	var adt$1 = Adt.generate([
		{ domRange: ['rng'] },
		{
			relative: ['startSitu', 'finishSitu']
		},
		{
			exact: ['start', 'soffset', 'finish', 'foffset']
		}
	])
	var exactFromRange = function(simRange) {
		return adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset)
	}
	var getStart = function(selection) {
		return selection.match({
			domRange: function(rng) {
				return SugarElement.fromDom(rng.startContainer)
			},
			relative: function(startSitu, _finishSitu) {
				return Situ.getStart(startSitu)
			},
			exact: function(start, _soffset, _finish, _foffset) {
				return start
			}
		})
	}
	var domRange = adt$1.domRange
	var relative = adt$1.relative
	var exact = adt$1.exact
	var getWin$1 = function(selection) {
		var start = getStart(selection)
		return defaultView(start)
	}
	var range = SimRange.create
	var SimSelection = {
		domRange: domRange,
		relative: relative,
		exact: exact,
		exactFromRange: exactFromRange,
		getWin: getWin$1,
		range: range
	}

	var beforeSpecial = function(element, offset) {
		var name = name$1(element)
		if ('input' === name) {
			return Situ.after(element)
		} else if (!contains$1(['br', 'img'], name)) {
			return Situ.on(element, offset)
		} else {
			return offset === 0 ? Situ.before(element) : Situ.after(element)
		}
	}
	var preprocessExact = function(start, soffset, finish, foffset) {
		var startSitu = beforeSpecial(start, soffset)
		var finishSitu = beforeSpecial(finish, foffset)
		return SimSelection.relative(startSitu, finishSitu)
	}

	var makeRange = function(start, soffset, finish, foffset) {
		var doc = owner$2(start)
		var rng = doc.dom.createRange()
		rng.setStart(start.dom, soffset)
		rng.setEnd(finish.dom, foffset)
		return rng
	}
	var after = function(start, soffset, finish, foffset) {
		var r = makeRange(start, soffset, finish, foffset)
		var same = eq(start, finish) && soffset === foffset
		return r.collapsed && !same
	}

	var getNativeSelection = function(win) {
		return Optional.from(win.getSelection())
	}
	var doSetNativeRange = function(win, rng) {
		getNativeSelection(win).each(function(selection) {
			selection.removeAllRanges()
			selection.addRange(rng)
		})
	}
	var doSetRange = function(win, start, soffset, finish, foffset) {
		var rng = exactToNative(win, start, soffset, finish, foffset)
		doSetNativeRange(win, rng)
	}
	var setLegacyRtlRange = function(win, selection, start, soffset, finish, foffset) {
		selection.collapse(start.dom, soffset)
		selection.extend(finish.dom, foffset)
	}
	var setRangeFromRelative = function(win, relative) {
		return diagnose(win, relative).match({
			ltr: function(start, soffset, finish, foffset) {
				doSetRange(win, start, soffset, finish, foffset)
			},
			rtl: function(start, soffset, finish, foffset) {
				getNativeSelection(win).each(function(selection) {
					if (selection.setBaseAndExtent) {
						selection.setBaseAndExtent(start.dom, soffset, finish.dom, foffset)
					} else if (selection.extend) {
						try {
							setLegacyRtlRange(win, selection, start, soffset, finish, foffset)
						} catch (e) {
							doSetRange(win, finish, foffset, start, soffset)
						}
					} else {
						doSetRange(win, finish, foffset, start, soffset)
					}
				})
			}
		})
	}
	var setExact = function(win, start, soffset, finish, foffset) {
		var relative = preprocessExact(start, soffset, finish, foffset)
		setRangeFromRelative(win, relative)
	}
	var readRange = function(selection) {
		if (selection.rangeCount > 0) {
			var firstRng = selection.getRangeAt(0)
			var lastRng = selection.getRangeAt(selection.rangeCount - 1)
			return Optional.some(
				SimRange.create(
					SugarElement.fromDom(firstRng.startContainer),
					firstRng.startOffset,
					SugarElement.fromDom(lastRng.endContainer),
					lastRng.endOffset
				)
			)
		} else {
			return Optional.none()
		}
	}
	var doGetExact = function(selection) {
		if (selection.anchorNode === null || selection.focusNode === null) {
			return readRange(selection)
		} else {
			var anchor = SugarElement.fromDom(selection.anchorNode)
			var focus_1 = SugarElement.fromDom(selection.focusNode)
			return after(anchor, selection.anchorOffset, focus_1, selection.focusOffset)
				? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus_1, selection.focusOffset))
				: readRange(selection)
		}
	}
	var getExact = function(win) {
		return getNativeSelection(win)
			.filter(function(sel) {
				return sel.rangeCount > 0
			})
			.bind(doGetExact)
	}
	var get = function(win) {
		return getExact(win).map(function(range) {
			return SimSelection.exact(range.start, range.soffset, range.finish, range.foffset)
		})
	}
	var getFirstRect = function(win, selection) {
		var rng = asLtrRange(win, selection)
		return getFirstRect$1(rng)
	}
	var clear = function(win) {
		getNativeSelection(win).each(function(selection) {
			return selection.removeAllRanges()
		})
	}

	var getBodyFromFrame = function(frame) {
		return Optional.some(SugarElement.fromDom(frame.dom.contentWindow.document.body))
	}
	var getDocFromFrame = function(frame) {
		return Optional.some(SugarElement.fromDom(frame.dom.contentWindow.document))
	}
	var getWinFromFrame = function(frame) {
		return Optional.from(frame.dom.contentWindow)
	}
	var getSelectionFromFrame = function(frame) {
		var optWin = getWinFromFrame(frame)
		return optWin.bind(getExact)
	}
	var getFrame = function(editor) {
		return editor.getFrame()
	}
	var getOrDerive = function(name, f) {
		return function(editor) {
			var g = editor[name].getOrThunk(function() {
				var frame = getFrame(editor)
				return function() {
					return f(frame)
				}
			})
			return g()
		}
	}
	var getOrListen = function(editor, doc, name, type) {
		return editor[name].getOrThunk(function() {
			return function(handler) {
				return bind(doc, type, handler)
			}
		})
	}
	var getActiveApi = function(editor) {
		var frame = getFrame(editor)
		var tryFallbackBox = function(win) {
			var isCollapsed = function(sel) {
				return eq(sel.start, sel.finish) && sel.soffset === sel.foffset
			}
			var toStartRect = function(sel) {
				var rect = sel.start.dom.getBoundingClientRect()
				return rect.width > 0 || rect.height > 0 ? Optional.some(rect) : Optional.none()
			}
			return getExact(win)
				.filter(isCollapsed)
				.bind(toStartRect)
		}
		return getBodyFromFrame(frame).bind(function(body) {
			return getDocFromFrame(frame).bind(function(doc) {
				return getWinFromFrame(frame).map(function(win) {
					var html = SugarElement.fromDom(doc.dom.documentElement)
					var getCursorBox = editor.getCursorBox.getOrThunk(function() {
						return function() {
							return get(win).bind(function(sel) {
								return getFirstRect(win, sel).orThunk(function() {
									return tryFallbackBox(win)
								})
							})
						}
					})
					var setSelection = editor.setSelection.getOrThunk(function() {
						return function(start, soffset, finish, foffset) {
							setExact(win, start, soffset, finish, foffset)
						}
					})
					var clearSelection = editor.clearSelection.getOrThunk(function() {
						return function() {
							clear(win)
						}
					})
					return {
						body: body,
						doc: doc,
						win: win,
						html: html,
						getSelection: curry(getSelectionFromFrame, frame),
						setSelection: setSelection,
						clearSelection: clearSelection,
						frame: frame,
						onKeyup: getOrListen(editor, doc, 'onKeyup', 'keyup'),
						onNodeChanged: getOrListen(editor, doc, 'onNodeChanged', 'SelectionChange'),
						onDomChanged: editor.onDomChanged,
						onScrollToCursor: editor.onScrollToCursor,
						onScrollToElement: editor.onScrollToElement,
						onToReading: editor.onToReading,
						onToEditing: editor.onToEditing,
						onToolbarScrollStart: editor.onToolbarScrollStart,
						onTouchContent: editor.onTouchContent,
						onTapContent: editor.onTapContent,
						onTouchToolstrip: editor.onTouchToolstrip,
						getCursorBox: getCursorBox
					}
				})
			})
		})
	}
	var getWin = getOrDerive('getWin', getWinFromFrame)

	var tag = function() {
		var head = first$1('head').getOrDie()
		var nu = function() {
			var meta = SugarElement.fromTag('meta')
			set$8(meta, 'name', 'viewport')
			append$2(head, meta)
			return meta
		}
		var element = first$1('meta[name="viewport"]').getOrThunk(nu)
		var backup = get$b(element, 'content')
		var maximize = function() {
			set$8(element, 'content', 'width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0')
		}
		var restore = function() {
			if (backup !== undefined && backup !== null && backup.length > 0) {
				set$8(element, 'content', backup)
			} else {
				set$8(element, 'content', 'user-scalable=yes')
			}
		}
		return {
			maximize: maximize,
			restore: restore
		}
	}

	var attr = 'data-ephox-mobile-fullscreen-style'
	var siblingStyles = 'display:none!important;'
	var ancestorPosition = 'position:absolute!important;'
	var ancestorStyles =
		'top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;'
	var bgFallback = 'background-color:rgb(255,255,255)!important;'
	var isAndroid = detect$1().os.isAndroid()
	var matchColor = function(editorBody) {
		var color = get$8(editorBody, 'background-color')
		return color !== undefined && color !== '' ? 'background-color:' + color + '!important' : bgFallback
	}
	var clobberStyles = function(container, editorBody) {
		var gatherSiblings = function(element) {
			return siblings(element, '*')
		}
		var clobber = function(clobberStyle) {
			return function(element) {
				var styles = get$b(element, 'style')
				var backup = styles === undefined ? 'no-styles' : styles.trim()
				if (backup === clobberStyle) {
					return
				} else {
					set$8(element, attr, backup)
					set$8(element, 'style', clobberStyle)
				}
			}
		}
		var ancestors$1 = ancestors(container, '*')
		var siblings$1 = bind$3(ancestors$1, gatherSiblings)
		var bgColor = matchColor(editorBody)
		each$1(siblings$1, clobber(siblingStyles))
		each$1(ancestors$1, clobber(ancestorPosition + ancestorStyles + bgColor))
		var containerStyles = isAndroid === true ? '' : ancestorPosition
		clobber(containerStyles + ancestorStyles + bgColor)(container)
	}
	var restoreStyles = function() {
		var clobberedEls = all('[' + attr + ']')
		each$1(clobberedEls, function(element) {
			var restore = get$b(element, attr)
			if (restore !== 'no-styles') {
				set$8(element, 'style', restore)
			} else {
				remove$6(element, 'style')
			}
			remove$6(element, attr)
		})
	}

	var DelayedFunction = function(fun, delay) {
		var ref = null
		var schedule = function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			ref = setTimeout(function() {
				fun.apply(null, args)
				ref = null
			}, delay)
		}
		var cancel = function() {
			if (ref !== null) {
				clearTimeout(ref)
				ref = null
			}
		}
		return {
			cancel: cancel,
			schedule: schedule
		}
	}

	var SIGNIFICANT_MOVE = 5
	var LONGPRESS_DELAY = 400
	var getTouch = function(event) {
		var raw = event.raw
		if (raw.touches === undefined || raw.touches.length !== 1) {
			return Optional.none()
		}
		return Optional.some(raw.touches[0])
	}
	var isFarEnough = function(touch, data) {
		var distX = Math.abs(touch.clientX - data.x)
		var distY = Math.abs(touch.clientY - data.y)
		return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE
	}
	var monitor$1 = function(settings) {
		var startData = value()
		var longpressFired = Cell(false)
		var longpress$1 = DelayedFunction(function(event) {
			settings.triggerEvent(longpress(), event)
			longpressFired.set(true)
		}, LONGPRESS_DELAY)
		var handleTouchstart = function(event) {
			getTouch(event).each(function(touch) {
				longpress$1.cancel()
				var data = {
					x: touch.clientX,
					y: touch.clientY,
					target: event.target
				}
				longpress$1.schedule(event)
				longpressFired.set(false)
				startData.set(data)
			})
			return Optional.none()
		}
		var handleTouchmove = function(event) {
			longpress$1.cancel()
			getTouch(event).each(function(touch) {
				startData.on(function(data) {
					if (isFarEnough(touch, data)) {
						startData.clear()
					}
				})
			})
			return Optional.none()
		}
		var handleTouchend = function(event) {
			longpress$1.cancel()
			var isSame = function(data) {
				return eq(data.target, event.target)
			}
			return startData
				.get()
				.filter(isSame)
				.map(function(_data) {
					if (longpressFired.get()) {
						event.prevent()
						return false
					} else {
						return settings.triggerEvent(tap(), event)
					}
				})
		}
		var handlers = wrapAll([
			{
				key: touchstart(),
				value: handleTouchstart
			},
			{
				key: touchmove(),
				value: handleTouchmove
			},
			{
				key: touchend(),
				value: handleTouchend
			}
		])
		var fireIfReady = function(event, type) {
			return get$c(handlers, type).bind(function(handler) {
				return handler(event)
			})
		}
		return { fireIfReady: fireIfReady }
	}

	var monitor = function(editorApi) {
		var tapEvent = monitor$1({
			triggerEvent: function(type, evt) {
				editorApi.onTapContent(evt)
			}
		})
		var onTouchend = function() {
			return bind(editorApi.body, 'touchend', function(evt) {
				tapEvent.fireIfReady(evt, 'touchend')
			})
		}
		var onTouchmove = function() {
			return bind(editorApi.body, 'touchmove', function(evt) {
				tapEvent.fireIfReady(evt, 'touchmove')
			})
		}
		var fireTouchstart = function(evt) {
			tapEvent.fireIfReady(evt, 'touchstart')
		}
		return {
			fireTouchstart: fireTouchstart,
			onTouchend: onTouchend,
			onTouchmove: onTouchmove
		}
	}

	var isAndroid6 = detect$1().os.version.major >= 6
	var initEvents$1 = function(editorApi, toolstrip, alloy) {
		var tapping = monitor(editorApi)
		var outerDoc = owner$2(toolstrip)
		var isRanged = function(sel) {
			return !eq(sel.start, sel.finish) || sel.soffset !== sel.foffset
		}
		var hasRangeInUi = function() {
			return active(outerDoc)
				.filter(function(input) {
					return name$1(input) === 'input'
				})
				.exists(function(input) {
					return input.dom.selectionStart !== input.dom.selectionEnd
				})
		}
		var updateMargin = function() {
			var rangeInContent = editorApi.doc.dom.hasFocus() && editorApi.getSelection().exists(isRanged)
			alloy.getByDom(toolstrip).each((rangeInContent || hasRangeInUi()) === true ? Toggling.on : Toggling.off)
		}
		var listeners = [
			bind(editorApi.body, 'touchstart', function(evt) {
				editorApi.onTouchContent()
				tapping.fireTouchstart(evt)
			}),
			tapping.onTouchmove(),
			tapping.onTouchend(),
			bind(toolstrip, 'touchstart', function(_evt) {
				editorApi.onTouchToolstrip()
			}),
			editorApi.onToReading(function() {
				blur$1(editorApi.body)
			}),
			editorApi.onToEditing(noop),
			editorApi.onScrollToCursor(function(tinyEvent) {
				tinyEvent.preventDefault()
				editorApi.getCursorBox().each(function(bounds) {
					var cWin = editorApi.win
					var isOutside = bounds.top > cWin.innerHeight || bounds.bottom > cWin.innerHeight
					var cScrollBy = isOutside ? bounds.bottom - cWin.innerHeight + 50 : 0
					if (cScrollBy !== 0) {
						cWin.scrollTo(cWin.pageXOffset, cWin.pageYOffset + cScrollBy)
					}
				})
			})
		].concat(
			isAndroid6 === true
				? []
				: [
						bind(SugarElement.fromDom(editorApi.win), 'blur', function() {
							alloy.getByDom(toolstrip).each(Toggling.off)
						}),
						bind(outerDoc, 'select', updateMargin),
						bind(editorApi.doc, 'selectionchange', updateMargin)
				  ]
		)
		var destroy = function() {
			each$1(listeners, function(l) {
				l.unbind()
			})
		}
		return { destroy: destroy }
	}

	var safeParse = function(element, attribute) {
		var parsed = parseInt(get$b(element, attribute), 10)
		return isNaN(parsed) ? 0 : parsed
	}

	var COLLAPSED_WIDTH = 2
	var collapsedRect = function(rect) {
		return __assign(__assign({}, rect), { width: COLLAPSED_WIDTH })
	}
	var toRect = function(rawRect) {
		return {
			left: rawRect.left,
			top: rawRect.top,
			right: rawRect.right,
			bottom: rawRect.bottom,
			width: rawRect.width,
			height: rawRect.height
		}
	}
	var getRectsFromRange = function(range) {
		if (!range.collapsed) {
			return map$2(range.getClientRects(), toRect)
		} else {
			var start_1 = SugarElement.fromDom(range.startContainer)
			return parent(start_1)
				.bind(function(parent) {
					var selection = SimSelection.exact(start_1, range.startOffset, parent, getEnd(parent))
					var optRect = getFirstRect(range.startContainer.ownerDocument.defaultView, selection)
					return optRect.map(collapsedRect).map(pure$2)
				})
				.getOr([])
		}
	}
	var getRectangles = function(cWin) {
		var sel = cWin.getSelection()
		return sel !== undefined && sel.rangeCount > 0 ? getRectsFromRange(sel.getRangeAt(0)) : []
	}

	var autocompleteHack = function() {
		return function(f) {
			global$2.setTimeout(function() {
				f()
			}, 0)
		}
	}
	var resume$1 = function(cWin) {
		cWin.focus()
		var iBody = SugarElement.fromDom(cWin.document.body)
		var inInput = active().exists(function(elem) {
			return contains$1(['input', 'textarea'], name$1(elem))
		})
		var transaction = inInput ? autocompleteHack() : apply$1
		transaction(function() {
			active().each(blur$1)
			focus$3(iBody)
		})
	}

	var EXTRA_SPACING = 50
	var data = 'data-' + resolve('last-outer-height')
	var setLastHeight = function(cBody, value) {
		set$8(cBody, data, value)
	}
	var getLastHeight = function(cBody) {
		return safeParse(cBody, data)
	}
	var getBoundsFrom = function(rect) {
		return {
			top: rect.top,
			bottom: rect.top + rect.height
		}
	}
	var getBounds = function(cWin) {
		var rects = getRectangles(cWin)
		return rects.length > 0 ? Optional.some(rects[0]).map(getBoundsFrom) : Optional.none()
	}
	var findDelta = function(outerWindow, cBody) {
		var last = getLastHeight(cBody)
		var current = outerWindow.innerHeight
		return last > current ? Optional.some(last - current) : Optional.none()
	}
	var calculate = function(cWin, bounds, delta) {
		var isOutside = bounds.top > cWin.innerHeight || bounds.bottom > cWin.innerHeight
		return isOutside ? Math.min(delta, bounds.bottom - cWin.innerHeight + EXTRA_SPACING) : 0
	}
	var setup$2 = function(outerWindow, cWin) {
		var cBody = SugarElement.fromDom(cWin.document.body)
		var toEditing = function() {
			resume$1(cWin)
		}
		var onResize = bind(SugarElement.fromDom(outerWindow), 'resize', function() {
			findDelta(outerWindow, cBody).each(function(delta) {
				getBounds(cWin).each(function(bounds) {
					var cScrollBy = calculate(cWin, bounds, delta)
					if (cScrollBy !== 0) {
						cWin.scrollTo(cWin.pageXOffset, cWin.pageYOffset + cScrollBy)
					}
				})
			})
			setLastHeight(cBody, outerWindow.innerHeight)
		})
		setLastHeight(cBody, outerWindow.innerHeight)
		var destroy = function() {
			onResize.unbind()
		}
		return {
			toEditing: toEditing,
			destroy: destroy
		}
	}

	var create$2 = function(platform, mask) {
		var meta = tag()
		var androidApi = api$2()
		var androidEvents = api$2()
		var enter = function() {
			mask.hide()
			add$1(platform.container, resolve('fullscreen-maximized'))
			add$1(platform.container, resolve('android-maximized'))
			meta.maximize()
			add$1(platform.body, resolve('android-scroll-reload'))
			androidApi.set(setup$2(platform.win, getWin(platform.editor).getOrDie('no')))
			getActiveApi(platform.editor).each(function(editorApi) {
				clobberStyles(platform.container, editorApi.body)
				androidEvents.set(initEvents$1(editorApi, platform.toolstrip, platform.alloy))
			})
		}
		var exit = function() {
			meta.restore()
			mask.show()
			remove$3(platform.container, resolve('fullscreen-maximized'))
			remove$3(platform.container, resolve('android-maximized'))
			restoreStyles()
			remove$3(platform.body, resolve('android-scroll-reload'))
			androidEvents.clear()
			androidApi.clear()
		}
		return {
			enter: enter,
			exit: exit
		}
	}

	var first = function(fn, rate) {
		var timer = null
		var cancel = function() {
			if (!isNull(timer)) {
				clearTimeout(timer)
				timer = null
			}
		}
		var throttle = function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			if (isNull(timer)) {
				timer = setTimeout(function() {
					timer = null
					fn.apply(null, args)
				}, rate)
			}
		}
		return {
			cancel: cancel,
			throttle: throttle
		}
	}
	var last = function(fn, rate) {
		var timer = null
		var cancel = function() {
			if (!isNull(timer)) {
				clearTimeout(timer)
				timer = null
			}
		}
		var throttle = function() {
			var args = []
			for (var _i = 0; _i < arguments.length; _i++) {
				args[_i] = arguments[_i]
			}
			cancel()
			timer = setTimeout(function() {
				timer = null
				fn.apply(null, args)
			}, rate)
		}
		return {
			cancel: cancel,
			throttle: throttle
		}
	}

	var sketch = function(onView, _translate) {
		var memIcon = record(
			Container.sketch({
				dom: dom$1('<div aria-hidden="true" class="${prefix}-mask-tap-icon"></div>'),
				containerBehaviours: derive$2([
					Toggling.config({
						toggleClass: resolve('mask-tap-icon-selected'),
						toggleOnExecute: false
					})
				])
			})
		)
		var onViewThrottle = first(onView, 200)
		return Container.sketch({
			dom: dom$1('<div class="${prefix}-disabled-mask"></div>'),
			components: [
				Container.sketch({
					dom: dom$1('<div class="${prefix}-content-container"></div>'),
					components: [
						Button.sketch({
							dom: dom$1('<div class="${prefix}-content-tap-section"></div>'),
							components: [memIcon.asSpec()],
							action: function(_button) {
								onViewThrottle.throttle()
							},
							buttonBehaviours: derive$2([
								Toggling.config({ toggleClass: resolve('mask-tap-icon-selected') })
							])
						})
					]
				})
			]
		})
	}

	var unbindNoop = constant$1({ unbind: noop })
	var MobileSchema = objOf([
		requiredObjOf('editor', [
			required$1('getFrame'),
			option('getBody'),
			option('getDoc'),
			option('getWin'),
			option('getSelection'),
			option('setSelection'),
			option('clearSelection'),
			option('cursorSaver'),
			option('onKeyup'),
			option('onNodeChanged'),
			option('getCursorBox'),
			required$1('onDomChanged'),
			defaulted('onTouchContent', noop),
			defaulted('onTapContent', noop),
			defaulted('onTouchToolstrip', noop),
			defaulted('onScrollToCursor', unbindNoop),
			defaulted('onScrollToElement', unbindNoop),
			defaulted('onToEditing', unbindNoop),
			defaulted('onToReading', unbindNoop),
			defaulted('onToolbarScrollStart', identity)
		]),
		required$1('socket'),
		required$1('toolstrip'),
		required$1('dropup'),
		required$1('toolbar'),
		required$1('container'),
		required$1('alloy'),
		customField('win', function(spec) {
			return owner$2(spec.socket).dom.defaultView
		}),
		customField('body', function(spec) {
			return SugarElement.fromDom(spec.socket.dom.ownerDocument.body)
		}),
		defaulted('translate', identity),
		defaulted('setReadOnly', noop),
		defaulted('readOnlyOnInit', always)
	])

	var produce$1 = function(raw) {
		var mobile = asRawOrDie$1('Getting AndroidWebapp schema', MobileSchema, raw)
		set$5(mobile.toolstrip, 'width', '100%')
		var onTap = function() {
			mobile.setReadOnly(mobile.readOnlyOnInit())
			mode.enter()
		}
		var mask = build$1(sketch(onTap, mobile.translate))
		mobile.alloy.add(mask)
		var maskApi = {
			show: function() {
				mobile.alloy.add(mask)
			},
			hide: function() {
				mobile.alloy.remove(mask)
			}
		}
		append$2(mobile.container, mask.element)
		var mode = create$2(mobile, maskApi)
		return {
			setReadOnly: mobile.setReadOnly,
			refreshStructure: noop,
			enter: mode.enter,
			exit: mode.exit,
			destroy: noop
		}
	}

	var schema$1 = constant$1([required$1('dom'), defaulted('shell', true), field$1('toolbarBehaviours', [Replacing])])
	var enhanceGroups = function() {
		return { behaviours: derive$2([Replacing.config({})]) }
	}
	var parts$1 = constant$1([
		optional({
			name: 'groups',
			overrides: enhanceGroups
		})
	])

	var factory$1 = function(detail, components, _spec, _externals) {
		var setGroups = function(toolbar, groups) {
			getGroupContainer(toolbar).fold(
				function() {
					console.error(
						'Toolbar was defined to not be a shell, but no groups container was specified in components'
					)
					throw new Error(
						'Toolbar was defined to not be a shell, but no groups container was specified in components'
					)
				},
				function(container) {
					Replacing.set(container, groups)
				}
			)
		}
		var getGroupContainer = function(component) {
			return detail.shell ? Optional.some(component) : getPart(component, detail, 'groups')
		}
		var extra = detail.shell
			? {
					behaviours: [Replacing.config({})],
					components: []
			  }
			: {
					behaviours: [],
					components: components
			  }
		return {
			uid: detail.uid,
			dom: detail.dom,
			components: extra.components,
			behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
			apis: { setGroups: setGroups },
			domModification: { attributes: { role: 'group' } }
		}
	}
	var Toolbar = composite({
		name: 'Toolbar',
		configFields: schema$1(),
		partFields: parts$1(),
		factory: factory$1,
		apis: {
			setGroups: function(apis, toolbar, groups) {
				apis.setGroups(toolbar, groups)
			}
		}
	})

	var schema = constant$1([required$1('items'), markers(['itemSelector']), field$1('tgroupBehaviours', [Keying])])
	var parts = constant$1([
		group({
			name: 'items',
			unit: 'item'
		})
	])

	var factory = function(detail, components, _spec, _externals) {
		return {
			uid: detail.uid,
			dom: detail.dom,
			components: components,
			behaviours: augment(detail.tgroupBehaviours, [
				Keying.config({
					mode: 'flow',
					selector: detail.markers.itemSelector
				})
			]),
			domModification: { attributes: { role: 'toolbar' } }
		}
	}
	var ToolbarGroup = composite({
		name: 'ToolbarGroup',
		configFields: schema(),
		partFields: parts(),
		factory: factory
	})

	var dataHorizontal = 'data-' + resolve('horizontal-scroll')
	var canScrollVertically = function(container) {
		container.dom.scrollTop = 1
		var result = container.dom.scrollTop !== 0
		container.dom.scrollTop = 0
		return result
	}
	var canScrollHorizontally = function(container) {
		container.dom.scrollLeft = 1
		var result = container.dom.scrollLeft !== 0
		container.dom.scrollLeft = 0
		return result
	}
	var hasVerticalScroll = function(container) {
		return container.dom.scrollTop > 0 || canScrollVertically(container)
	}
	var hasHorizontalScroll = function(container) {
		return container.dom.scrollLeft > 0 || canScrollHorizontally(container)
	}
	var markAsHorizontal = function(container) {
		set$8(container, dataHorizontal, 'true')
	}
	var hasScroll = function(container) {
		return get$b(container, dataHorizontal) === 'true'
			? hasHorizontalScroll(container)
			: hasVerticalScroll(container)
	}
	var exclusive = function(scope, selector) {
		return bind(scope, 'touchmove', function(event) {
			closest$1(event.target, selector)
				.filter(hasScroll)
				.fold(function() {
					event.prevent()
				}, noop)
		})
	}

	var ScrollingToolbar = function() {
		var makeGroup = function(gSpec) {
			var scrollClass = gSpec.scrollable === true ? '${prefix}-toolbar-scrollable-group' : ''
			return {
				dom: dom$1(
					'<div aria-label="' + gSpec.label + '" class="${prefix}-toolbar-group ' + scrollClass + '"></div>'
				),
				tgroupBehaviours: derive$2([
					config(
						'adhoc-scrollable-toolbar',
						gSpec.scrollable === true
							? [
									runOnInit(function(component, _simulatedEvent) {
										set$5(component.element, 'overflow-x', 'auto')
										markAsHorizontal(component.element)
										register$2(component.element)
									})
							  ]
							: []
					)
				]),
				components: [Container.sketch({ components: [ToolbarGroup.parts.items({})] })],
				markers: { itemSelector: '.' + resolve('toolbar-group-item') },
				items: gSpec.items
			}
		}
		var toolbar = build$1(
			Toolbar.sketch({
				dom: dom$1('<div class="${prefix}-toolbar"></div>'),
				components: [Toolbar.parts.groups({})],
				toolbarBehaviours: derive$2([
					Toggling.config({
						toggleClass: resolve('context-toolbar'),
						toggleOnExecute: false,
						aria: { mode: 'none' }
					}),
					Keying.config({ mode: 'cyclic' })
				]),
				shell: true
			})
		)
		var wrapper = build$1(
			Container.sketch({
				dom: { classes: [resolve('toolstrip')] },
				components: [premade(toolbar)],
				containerBehaviours: derive$2([
					Toggling.config({
						toggleClass: resolve('android-selection-context-toolbar'),
						toggleOnExecute: false
					})
				])
			})
		)
		var resetGroups = function() {
			Toolbar.setGroups(toolbar, initGroups.get())
			Toggling.off(toolbar)
		}
		var initGroups = Cell([])
		var setGroups = function(gs) {
			initGroups.set(gs)
			resetGroups()
		}
		var createGroups = function(gs) {
			return map$2(gs, compose(ToolbarGroup.sketch, makeGroup))
		}
		var refresh = function() {}
		var setContextToolbar = function(gs) {
			Toggling.on(toolbar)
			Toolbar.setGroups(toolbar, gs)
		}
		var restoreToolbar = function() {
			if (Toggling.isOn(toolbar)) {
				resetGroups()
			}
		}
		var focus = function() {
			Keying.focusIn(toolbar)
		}
		return {
			wrapper: wrapper,
			toolbar: toolbar,
			createGroups: createGroups,
			setGroups: setGroups,
			setContextToolbar: setContextToolbar,
			restoreToolbar: restoreToolbar,
			refresh: refresh,
			focus: focus
		}
	}

	var makeEditSwitch = function(webapp) {
		return build$1(
			Button.sketch({
				dom: dom$1('<div class="${prefix}-mask-edit-icon ${prefix}-icon"></div>'),
				action: function() {
					webapp.run(function(w) {
						w.setReadOnly(false)
					})
				}
			})
		)
	}
	var makeSocket = function() {
		return build$1(
			Container.sketch({
				dom: dom$1('<div class="${prefix}-editor-socket"></div>'),
				components: [],
				containerBehaviours: derive$2([Replacing.config({})])
			})
		)
	}
	var showEdit = function(socket, switchToEdit) {
		Replacing.append(socket, premade(switchToEdit))
	}
	var hideEdit = function(socket, switchToEdit) {
		Replacing.remove(socket, switchToEdit)
	}
	var updateMode = function(socket, switchToEdit, readOnly, root) {
		var swap = readOnly === true ? Swapping.toAlpha : Swapping.toOmega
		swap(root)
		var f = readOnly ? showEdit : hideEdit
		f(socket, switchToEdit)
	}

	var getAnimationRoot = function(component, slideConfig) {
		return slideConfig.getAnimationRoot.fold(
			function() {
				return component.element
			},
			function(get) {
				return get(component)
			}
		)
	}

	var getDimensionProperty = function(slideConfig) {
		return slideConfig.dimension.property
	}
	var getDimension = function(slideConfig, elem) {
		return slideConfig.dimension.getDimension(elem)
	}
	var disableTransitions = function(component, slideConfig) {
		var root = getAnimationRoot(component, slideConfig)
		remove$1(root, [slideConfig.shrinkingClass, slideConfig.growingClass])
	}
	var setShrunk = function(component, slideConfig) {
		remove$3(component.element, slideConfig.openClass)
		add$1(component.element, slideConfig.closedClass)
		set$5(component.element, getDimensionProperty(slideConfig), '0px')
		reflow(component.element)
	}
	var setGrown = function(component, slideConfig) {
		remove$3(component.element, slideConfig.closedClass)
		add$1(component.element, slideConfig.openClass)
		remove$2(component.element, getDimensionProperty(slideConfig))
	}
	var doImmediateShrink = function(component, slideConfig, slideState, _calculatedSize) {
		slideState.setCollapsed()
		set$5(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element))
		reflow(component.element)
		disableTransitions(component, slideConfig)
		setShrunk(component, slideConfig)
		slideConfig.onStartShrink(component)
		slideConfig.onShrunk(component)
	}
	var doStartShrink = function(component, slideConfig, slideState, calculatedSize) {
		var size = calculatedSize.getOrThunk(function() {
			return getDimension(slideConfig, component.element)
		})
		slideState.setCollapsed()
		set$5(component.element, getDimensionProperty(slideConfig), size)
		reflow(component.element)
		var root = getAnimationRoot(component, slideConfig)
		remove$3(root, slideConfig.growingClass)
		add$1(root, slideConfig.shrinkingClass)
		setShrunk(component, slideConfig)
		slideConfig.onStartShrink(component)
	}
	var doStartSmartShrink = function(component, slideConfig, slideState) {
		var size = getDimension(slideConfig, component.element)
		var shrinker = size === '0px' ? doImmediateShrink : doStartShrink
		shrinker(component, slideConfig, slideState, Optional.some(size))
	}
	var doStartGrow = function(component, slideConfig, slideState) {
		var root = getAnimationRoot(component, slideConfig)
		var wasShrinking = has(root, slideConfig.shrinkingClass)
		var beforeSize = getDimension(slideConfig, component.element)
		setGrown(component, slideConfig)
		var fullSize = getDimension(slideConfig, component.element)
		var startPartialGrow = function() {
			set$5(component.element, getDimensionProperty(slideConfig), beforeSize)
			reflow(component.element)
		}
		var startCompleteGrow = function() {
			setShrunk(component, slideConfig)
		}
		var setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow
		setStartSize()
		remove$3(root, slideConfig.shrinkingClass)
		add$1(root, slideConfig.growingClass)
		setGrown(component, slideConfig)
		set$5(component.element, getDimensionProperty(slideConfig), fullSize)
		slideState.setExpanded()
		slideConfig.onStartGrow(component)
	}
	var refresh$1 = function(component, slideConfig, slideState) {
		if (slideState.isExpanded()) {
			remove$2(component.element, getDimensionProperty(slideConfig))
			var fullSize = getDimension(slideConfig, component.element)
			set$5(component.element, getDimensionProperty(slideConfig), fullSize)
		}
	}
	var grow = function(component, slideConfig, slideState) {
		if (!slideState.isExpanded()) {
			doStartGrow(component, slideConfig, slideState)
		}
	}
	var shrink = function(component, slideConfig, slideState) {
		if (slideState.isExpanded()) {
			doStartSmartShrink(component, slideConfig, slideState)
		}
	}
	var immediateShrink = function(component, slideConfig, slideState) {
		if (slideState.isExpanded()) {
			doImmediateShrink(component, slideConfig, slideState)
		}
	}
	var hasGrown = function(component, slideConfig, slideState) {
		return slideState.isExpanded()
	}
	var hasShrunk = function(component, slideConfig, slideState) {
		return slideState.isCollapsed()
	}
	var isGrowing = function(component, slideConfig, _slideState) {
		var root = getAnimationRoot(component, slideConfig)
		return has(root, slideConfig.growingClass) === true
	}
	var isShrinking = function(component, slideConfig, _slideState) {
		var root = getAnimationRoot(component, slideConfig)
		return has(root, slideConfig.shrinkingClass) === true
	}
	var isTransitioning = function(component, slideConfig, slideState) {
		return isGrowing(component, slideConfig) || isShrinking(component, slideConfig)
	}
	var toggleGrow = function(component, slideConfig, slideState) {
		var f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow
		f(component, slideConfig, slideState)
	}

	var SlidingApis = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		refresh: refresh$1,
		grow: grow,
		shrink: shrink,
		immediateShrink: immediateShrink,
		hasGrown: hasGrown,
		hasShrunk: hasShrunk,
		isGrowing: isGrowing,
		isShrinking: isShrinking,
		isTransitioning: isTransitioning,
		toggleGrow: toggleGrow,
		disableTransitions: disableTransitions
	})

	var exhibit = function(base, slideConfig, _slideState) {
		var expanded = slideConfig.expanded
		return expanded
			? nu$3({
					classes: [slideConfig.openClass],
					styles: {}
			  })
			: nu$3({
					classes: [slideConfig.closedClass],
					styles: wrap(slideConfig.dimension.property, '0px')
			  })
	}
	var events = function(slideConfig, slideState) {
		return derive$3([
			runOnSource(transitionend(), function(component, simulatedEvent) {
				var raw = simulatedEvent.event.raw
				if (raw.propertyName === slideConfig.dimension.property) {
					disableTransitions(component, slideConfig)
					if (slideState.isExpanded()) {
						remove$2(component.element, slideConfig.dimension.property)
					}
					var notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk
					notify(component)
				}
			})
		])
	}

	var ActiveSliding = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		exhibit: exhibit,
		events: events
	})

	var SlidingSchema = [
		required$1('closedClass'),
		required$1('openClass'),
		required$1('shrinkingClass'),
		required$1('growingClass'),
		option('getAnimationRoot'),
		onHandler('onShrunk'),
		onHandler('onStartShrink'),
		onHandler('onGrown'),
		onHandler('onStartGrow'),
		defaulted('expanded', false),
		requiredOf(
			'dimension',
			choose$1('property', {
				width: [
					output('property', 'width'),
					output('getDimension', function(elem) {
						return get$5(elem) + 'px'
					})
				],
				height: [
					output('property', 'height'),
					output('getDimension', function(elem) {
						return get$7(elem) + 'px'
					})
				]
			})
		)
	]

	var init$1 = function(spec) {
		var state = Cell(spec.expanded)
		var readState = function() {
			return 'expanded: ' + state.get()
		}
		return nu$2({
			isExpanded: function() {
				return state.get() === true
			},
			isCollapsed: function() {
				return state.get() === false
			},
			setCollapsed: curry(state.set, false),
			setExpanded: curry(state.set, true),
			readState: readState
		})
	}

	var SlidingState = /*#__PURE__*/ Object.freeze({
		__proto__: null,
		init: init$1
	})

	var Sliding = create$5({
		fields: SlidingSchema,
		name: 'sliding',
		active: ActiveSliding,
		apis: SlidingApis,
		state: SlidingState
	})

	var build = function(refresh, scrollIntoView) {
		var dropup = build$1(
			Container.sketch({
				dom: {
					tag: 'div',
					classes: [resolve('dropup')]
				},
				components: [],
				containerBehaviours: derive$2([
					Replacing.config({}),
					Sliding.config({
						closedClass: resolve('dropup-closed'),
						openClass: resolve('dropup-open'),
						shrinkingClass: resolve('dropup-shrinking'),
						growingClass: resolve('dropup-growing'),
						dimension: { property: 'height' },
						onShrunk: function(component) {
							refresh()
							scrollIntoView()
							Replacing.set(component, [])
						},
						onGrown: function(_component) {
							refresh()
							scrollIntoView()
						}
					}),
					orientation(function(_component, _data) {
						disappear(noop)
					})
				])
			})
		)
		var appear = function(menu, update, component) {
			if (Sliding.hasShrunk(dropup) === true && Sliding.isTransitioning(dropup) === false) {
				window.requestAnimationFrame(function() {
					update(component)
					Replacing.set(dropup, [menu()])
					Sliding.grow(dropup)
				})
			}
		}
		var disappear = function(onReadyToShrink) {
			window.requestAnimationFrame(function() {
				onReadyToShrink()
				Sliding.shrink(dropup)
			})
		}
		return {
			appear: appear,
			disappear: disappear,
			component: dropup,
			element: dropup.element
		}
	}

	var closest = function(scope, selector, isRoot) {
		return closest$1(scope, selector, isRoot).isSome()
	}

	var isDangerous = function(event) {
		var keyEv = event.raw
		return (
			keyEv.which === BACKSPACE[0] &&
			!contains$1(['input', 'textarea'], name$1(event.target)) &&
			!closest(event.target, '[contenteditable="true"]')
		)
	}
	var isFirefox = function() {
		return detect$1().browser.isFirefox()
	}
	var bindFocus = function(container, handler) {
		if (isFirefox()) {
			return capture(container, 'focus', handler)
		} else {
			return bind(container, 'focusin', handler)
		}
	}
	var bindBlur = function(container, handler) {
		if (isFirefox()) {
			return capture(container, 'blur', handler)
		} else {
			return bind(container, 'focusout', handler)
		}
	}
	var setup$1 = function(container, rawSettings) {
		var settings = __assign({ stopBackspace: true }, rawSettings)
		var pointerEvents = [
			'touchstart',
			'touchmove',
			'touchend',
			'touchcancel',
			'gesturestart',
			'mousedown',
			'mouseup',
			'mouseover',
			'mousemove',
			'mouseout',
			'click'
		]
		var tapEvent = monitor$1(settings)
		var simpleEvents = map$2(
			pointerEvents.concat([
				'selectstart',
				'input',
				'contextmenu',
				'change',
				'transitionend',
				'transitioncancel',
				'drag',
				'dragstart',
				'dragend',
				'dragenter',
				'dragleave',
				'dragover',
				'drop',
				'keyup'
			]),
			function(type) {
				return bind(container, type, function(event) {
					tapEvent.fireIfReady(event, type).each(function(tapStopped) {
						if (tapStopped) {
							event.kill()
						}
					})
					var stopped = settings.triggerEvent(type, event)
					if (stopped) {
						event.kill()
					}
				})
			}
		)
		var pasteTimeout = value()
		var onPaste = bind(container, 'paste', function(event) {
			tapEvent.fireIfReady(event, 'paste').each(function(tapStopped) {
				if (tapStopped) {
					event.kill()
				}
			})
			var stopped = settings.triggerEvent('paste', event)
			if (stopped) {
				event.kill()
			}
			pasteTimeout.set(
				setTimeout(function() {
					settings.triggerEvent(postPaste(), event)
				}, 0)
			)
		})
		var onKeydown = bind(container, 'keydown', function(event) {
			var stopped = settings.triggerEvent('keydown', event)
			if (stopped) {
				event.kill()
			} else if (settings.stopBackspace && isDangerous(event)) {
				event.prevent()
			}
		})
		var onFocusIn = bindFocus(container, function(event) {
			var stopped = settings.triggerEvent('focusin', event)
			if (stopped) {
				event.kill()
			}
		})
		var focusoutTimeout = value()
		var onFocusOut = bindBlur(container, function(event) {
			var stopped = settings.triggerEvent('focusout', event)
			if (stopped) {
				event.kill()
			}
			focusoutTimeout.set(
				setTimeout(function() {
					settings.triggerEvent(postBlur(), event)
				}, 0)
			)
		})
		var unbind = function() {
			each$1(simpleEvents, function(e) {
				e.unbind()
			})
			onKeydown.unbind()
			onFocusIn.unbind()
			onFocusOut.unbind()
			onPaste.unbind()
			pasteTimeout.on(clearTimeout)
			focusoutTimeout.on(clearTimeout)
		}
		return { unbind: unbind }
	}

	var derive$1 = function(rawEvent, rawTarget) {
		var source = get$c(rawEvent, 'target').getOr(rawTarget)
		return Cell(source)
	}

	var fromSource = function(event, source) {
		var stopper = Cell(false)
		var cutter = Cell(false)
		var stop = function() {
			stopper.set(true)
		}
		var cut = function() {
			cutter.set(true)
		}
		return {
			stop: stop,
			cut: cut,
			isStopped: stopper.get,
			isCut: cutter.get,
			event: event,
			setSource: source.set,
			getSource: source.get
		}
	}
	var fromExternal = function(event) {
		var stopper = Cell(false)
		var stop = function() {
			stopper.set(true)
		}
		return {
			stop: stop,
			cut: noop,
			isStopped: stopper.get,
			isCut: never,
			event: event,
			setSource: die('Cannot set source of a broadcasted event'),
			getSource: die('Cannot get source of a broadcasted event')
		}
	}

	var adt = Adt.generate([{ stopped: [] }, { resume: ['element'] }, { complete: [] }])
	var doTriggerHandler = function(lookup, eventType, rawEvent, target, source, logger) {
		var handler = lookup(eventType, target)
		var simulatedEvent = fromSource(rawEvent, source)
		return handler.fold(
			function() {
				logger.logEventNoHandlers(eventType, target)
				return adt.complete()
			},
			function(handlerInfo) {
				var descHandler = handlerInfo.descHandler
				var eventHandler = getCurried(descHandler)
				eventHandler(simulatedEvent)
				if (simulatedEvent.isStopped()) {
					logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose)
					return adt.stopped()
				} else if (simulatedEvent.isCut()) {
					logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose)
					return adt.complete()
				} else {
					return parent(handlerInfo.element).fold(
						function() {
							logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose)
							return adt.complete()
						},
						function(parent) {
							logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose)
							return adt.resume(parent)
						}
					)
				}
			}
		)
	}
	var doTriggerOnUntilStopped = function(lookup, eventType, rawEvent, rawTarget, source, logger) {
		return doTriggerHandler(lookup, eventType, rawEvent, rawTarget, source, logger).fold(
			always,
			function(parent) {
				return doTriggerOnUntilStopped(lookup, eventType, rawEvent, parent, source, logger)
			},
			never
		)
	}
	var triggerHandler = function(lookup, eventType, rawEvent, target, logger) {
		var source = derive$1(rawEvent, target)
		return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger)
	}
	var broadcast = function(listeners, rawEvent, _logger) {
		var simulatedEvent = fromExternal(rawEvent)
		each$1(listeners, function(listener) {
			var descHandler = listener.descHandler
			var handler = getCurried(descHandler)
			handler(simulatedEvent)
		})
		return simulatedEvent.isStopped()
	}
	var triggerUntilStopped = function(lookup, eventType, rawEvent, logger) {
		return triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger)
	}
	var triggerOnUntilStopped = function(lookup, eventType, rawEvent, rawTarget, logger) {
		var source = derive$1(rawEvent, rawTarget)
		return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger)
	}

	var eventHandler = function(element, descHandler) {
		return {
			element: element,
			descHandler: descHandler
		}
	}
	var broadcastHandler = function(id, handler) {
		return {
			id: id,
			descHandler: handler
		}
	}
	var EventRegistry = function() {
		var registry = {}
		var registerId = function(extraArgs, id, events) {
			each(events, function(v, k) {
				var handlers = registry[k] !== undefined ? registry[k] : {}
				handlers[id] = curryArgs(v, extraArgs)
				registry[k] = handlers
			})
		}
		var findHandler = function(handlers, elem) {
			return read(elem)
				.bind(function(id) {
					return get$c(handlers, id)
				})
				.map(function(descHandler) {
					return eventHandler(elem, descHandler)
				})
		}
		var filterByType = function(type) {
			return get$c(registry, type)
				.map(function(handlers) {
					return mapToArray(handlers, function(f, id) {
						return broadcastHandler(id, f)
					})
				})
				.getOr([])
		}
		var find = function(isAboveRoot, type, target) {
			return get$c(registry, type).bind(function(handlers) {
				return closest$3(
					target,
					function(elem) {
						return findHandler(handlers, elem)
					},
					isAboveRoot
				)
			})
		}
		var unregisterId = function(id) {
			each(registry, function(handlersById, _eventName) {
				if (has$2(handlersById, id)) {
					delete handlersById[id]
				}
			})
		}
		return {
			registerId: registerId,
			unregisterId: unregisterId,
			filterByType: filterByType,
			find: find
		}
	}

	var Registry = function() {
		var events = EventRegistry()
		var components = {}
		var readOrTag = function(component) {
			var elem = component.element
			return read(elem).getOrThunk(function() {
				return write('uid-', component.element)
			})
		}
		var failOnDuplicate = function(component, tagId) {
			var conflict = components[tagId]
			if (conflict === component) {
				unregister(component)
			} else {
				throw new Error(
					'The tagId "' +
						tagId +
						'" is already used by: ' +
						element(conflict.element) +
						'\nCannot use it for: ' +
						element(component.element) +
						'\n' +
						'The conflicting element is' +
						(inBody(conflict.element) ? ' ' : ' not ') +
						'already in the DOM'
				)
			}
		}
		var register = function(component) {
			var tagId = readOrTag(component)
			if (hasNonNullableKey(components, tagId)) {
				failOnDuplicate(component, tagId)
			}
			var extraArgs = [component]
			events.registerId(extraArgs, tagId, component.events)
			components[tagId] = component
		}
		var unregister = function(component) {
			read(component.element).each(function(tagId) {
				delete components[tagId]
				events.unregisterId(tagId)
			})
		}
		var filter = function(type) {
			return events.filterByType(type)
		}
		var find = function(isAboveRoot, type, target) {
			return events.find(isAboveRoot, type, target)
		}
		var getById = function(id) {
			return get$c(components, id)
		}
		return {
			find: find,
			filter: filter,
			register: register,
			unregister: unregister,
			getById: getById
		}
	}

	var takeover$1 = function(root) {
		var isAboveRoot = function(el) {
			return parent(root.element).fold(always, function(parent) {
				return eq(el, parent)
			})
		}
		var registry = Registry()
		var lookup = function(eventName, target) {
			return registry.find(isAboveRoot, eventName, target)
		}
		var domEvents = setup$1(root.element, {
			triggerEvent: function(eventName, event) {
				return monitorEvent(eventName, event.target, function(logger) {
					return triggerUntilStopped(lookup, eventName, event, logger)
				})
			}
		})
		var systemApi = {
			debugInfo: constant$1('real'),
			triggerEvent: function(eventName, target, data) {
				monitorEvent(eventName, target, function(logger) {
					return triggerOnUntilStopped(lookup, eventName, data, target, logger)
				})
			},
			triggerFocus: function(target, originator) {
				read(target).fold(
					function() {
						focus$3(target)
					},
					function(_alloyId) {
						monitorEvent(focus$4(), target, function(logger) {
							triggerHandler(
								lookup,
								focus$4(),
								{
									originator: originator,
									kill: noop,
									prevent: noop,
									target: target
								},
								target,
								logger
							)
							return false
						})
					}
				)
			},
			triggerEscape: function(comp, simulatedEvent) {
				systemApi.triggerEvent('keydown', comp.element, simulatedEvent.event)
			},
			getByUid: function(uid) {
				return getByUid(uid)
			},
			getByDom: function(elem) {
				return getByDom(elem)
			},
			build: build$1,
			addToGui: function(c) {
				add(c)
			},
			removeFromGui: function(c) {
				remove(c)
			},
			addToWorld: function(c) {
				addToWorld(c)
			},
			removeFromWorld: function(c) {
				removeFromWorld(c)
			},
			broadcast: function(message) {
				broadcast$1(message)
			},
			broadcastOn: function(channels, message) {
				broadcastOn(channels, message)
			},
			broadcastEvent: function(eventName, event) {
				broadcastEvent(eventName, event)
			},
			isConnected: always
		}
		var addToWorld = function(component) {
			component.connect(systemApi)
			if (!isText(component.element)) {
				registry.register(component)
				each$1(component.components(), addToWorld)
				systemApi.triggerEvent(systemInit(), component.element, { target: component.element })
			}
		}
		var removeFromWorld = function(component) {
			if (!isText(component.element)) {
				each$1(component.components(), removeFromWorld)
				registry.unregister(component)
			}
			component.disconnect()
		}
		var add = function(component) {
			attach(root, component)
		}
		var remove = function(component) {
			detach(component)
		}
		var destroy = function() {
			domEvents.unbind()
			remove$7(root.element)
		}
		var broadcastData = function(data) {
			var receivers = registry.filter(receive$1())
			each$1(receivers, function(receiver) {
				var descHandler = receiver.descHandler
				var handler = getCurried(descHandler)
				handler(data)
			})
		}
		var broadcast$1 = function(message) {
			broadcastData({
				universal: true,
				data: message
			})
		}
		var broadcastOn = function(channels, message) {
			broadcastData({
				universal: false,
				channels: channels,
				data: message
			})
		}
		var broadcastEvent = function(eventName, event) {
			var listeners = registry.filter(eventName)
			return broadcast(listeners, event)
		}
		var getByUid = function(uid) {
			return registry.getById(uid).fold(function() {
				return Result.error(new Error('Could not find component with uid: "' + uid + '" in system.'))
			}, Result.value)
		}
		var getByDom = function(elem) {
			var uid = read(elem).getOr('not found')
			return getByUid(uid)
		}
		addToWorld(root)
		return {
			root: root,
			element: root.element,
			destroy: destroy,
			add: add,
			remove: remove,
			getByUid: getByUid,
			getByDom: getByDom,
			addToWorld: addToWorld,
			removeFromWorld: removeFromWorld,
			broadcast: broadcast$1,
			broadcastOn: broadcastOn,
			broadcastEvent: broadcastEvent
		}
	}

	var READ_ONLY_MODE_CLASS = resolve('readonly-mode')
	var EDIT_MODE_CLASS = resolve('edit-mode')
	function OuterContainer(spec) {
		var root = build$1(
			Container.sketch({
				dom: { classes: [resolve('outer-container')].concat(spec.classes) },
				containerBehaviours: derive$2([
					Swapping.config({
						alpha: READ_ONLY_MODE_CLASS,
						omega: EDIT_MODE_CLASS
					})
				])
			})
		)
		return takeover$1(root)
	}

	function AndroidRealm(scrollIntoView) {
		var alloy = OuterContainer({ classes: [resolve('android-container')] })
		var toolbar = ScrollingToolbar()
		var webapp = api$2()
		var switchToEdit = makeEditSwitch(webapp)
		var socket = makeSocket()
		var dropup = build(noop, scrollIntoView)
		alloy.add(toolbar.wrapper)
		alloy.add(socket)
		alloy.add(dropup.component)
		var setToolbarGroups = function(rawGroups) {
			var groups = toolbar.createGroups(rawGroups)
			toolbar.setGroups(groups)
		}
		var setContextToolbar = function(rawGroups) {
			var groups = toolbar.createGroups(rawGroups)
			toolbar.setContextToolbar(groups)
		}
		var focusToolbar = function() {
			toolbar.focus()
		}
		var restoreToolbar = function() {
			toolbar.restoreToolbar()
		}
		var init = function(spec) {
			webapp.set(produce$1(spec))
		}
		var exit = function() {
			webapp.run(function(w) {
				w.exit()
				Replacing.remove(socket, switchToEdit)
			})
		}
		var updateMode$1 = function(readOnly) {
			updateMode(socket, switchToEdit, readOnly, alloy.root)
		}
		return {
			system: alloy,
			element: alloy.element,
			init: init,
			exit: exit,
			setToolbarGroups: setToolbarGroups,
			setContextToolbar: setContextToolbar,
			focusToolbar: focusToolbar,
			restoreToolbar: restoreToolbar,
			updateMode: updateMode$1,
			socket: socket,
			dropup: dropup
		}
	}

	var input = function(parent, operation) {
		var input = SugarElement.fromTag('input')
		setAll(input, {
			opacity: '0',
			position: 'absolute',
			top: '-1000px',
			left: '-1000px'
		})
		append$2(parent, input)
		focus$3(input)
		operation(input)
		remove$7(input)
	}

	var refresh = function(winScope) {
		var sel = winScope.getSelection()
		if (sel.rangeCount > 0) {
			var br = sel.getRangeAt(0)
			var r = winScope.document.createRange()
			r.setStart(br.startContainer, br.startOffset)
			r.setEnd(br.endContainer, br.endOffset)
			sel.removeAllRanges()
			sel.addRange(r)
		}
	}

	var resume = function(cWin, frame) {
		active().each(function(active) {
			if (!eq(active, frame)) {
				blur$1(active)
			}
		})
		cWin.focus()
		focus$3(SugarElement.fromDom(cWin.document.body))
		refresh(cWin)
	}

	var stubborn = function(outerBody, cWin, page, frame) {
		var toEditing = function() {
			resume(cWin, frame)
		}
		var toReading = function() {
			input(outerBody, blur$1)
		}
		var captureInput = bind(page, 'keydown', function(evt) {
			if (!contains$1(['input', 'textarea'], name$1(evt.target))) {
				toEditing()
			}
		})
		var onToolbarTouch = noop
		var destroy = function() {
			captureInput.unbind()
		}
		return {
			toReading: toReading,
			toEditing: toEditing,
			onToolbarTouch: onToolbarTouch,
			destroy: destroy
		}
	}

	var initEvents = function(editorApi, iosApi, toolstrip, socket, _dropup) {
		var saveSelectionFirst = function() {
			iosApi.run(function(api) {
				api.highlightSelection()
			})
		}
		var refreshIosSelection = function() {
			iosApi.run(function(api) {
				api.refreshSelection()
			})
		}
		var scrollToY = function(yTop, height) {
			var y = yTop - socket.dom.scrollTop
			iosApi.run(function(api) {
				api.scrollIntoView(y, y + height)
			})
		}
		var scrollToElement = function(_target) {
			scrollToY(iosApi, socket)
		}
		var scrollToCursor = function() {
			editorApi.getCursorBox().each(function(box) {
				scrollToY(box.top, box.height)
			})
		}
		var clearSelection = function() {
			iosApi.run(function(api) {
				api.clearSelection()
			})
		}
		var clearAndRefresh = function() {
			clearSelection()
			refreshThrottle.throttle()
		}
		var refreshView = function() {
			scrollToCursor()
			iosApi.run(function(api) {
				api.syncHeight()
			})
		}
		var reposition = function() {
			var toolbarHeight = get$7(toolstrip)
			iosApi.run(function(api) {
				api.setViewportOffset(toolbarHeight)
			})
			refreshIosSelection()
			refreshView()
		}
		var toEditing = function() {
			iosApi.run(function(api) {
				api.toEditing()
			})
		}
		var toReading = function() {
			iosApi.run(function(api) {
				api.toReading()
			})
		}
		var onToolbarTouch = function(event) {
			iosApi.run(function(api) {
				api.onToolbarTouch(event)
			})
		}
		var tapping = monitor(editorApi)
		var refreshThrottle = last(refreshView, 300)
		var listeners = [
			editorApi.onKeyup(clearAndRefresh),
			editorApi.onNodeChanged(refreshIosSelection),
			editorApi.onDomChanged(refreshThrottle.throttle),
			editorApi.onDomChanged(refreshIosSelection),
			editorApi.onScrollToCursor(function(tinyEvent) {
				tinyEvent.preventDefault()
				refreshThrottle.throttle()
			}),
			editorApi.onScrollToElement(function(event) {
				scrollToElement(event.element)
			}),
			editorApi.onToEditing(toEditing),
			editorApi.onToReading(toReading),
			bind(editorApi.doc, 'touchend', function(touchEvent) {
				if (eq(editorApi.html, touchEvent.target) || eq(editorApi.body, touchEvent.target));
			}),
			bind(toolstrip, 'transitionend', function(transitionEvent) {
				if (transitionEvent.raw.propertyName === 'height') {
					reposition()
				}
			}),
			capture(toolstrip, 'touchstart', function(touchEvent) {
				saveSelectionFirst()
				onToolbarTouch(touchEvent)
				editorApi.onTouchToolstrip()
			}),
			bind(editorApi.body, 'touchstart', function(evt) {
				clearSelection()
				editorApi.onTouchContent()
				tapping.fireTouchstart(evt)
			}),
			tapping.onTouchmove(),
			tapping.onTouchend(),
			bind(editorApi.body, 'click', function(event) {
				event.kill()
			}),
			bind(toolstrip, 'touchmove', function() {
				editorApi.onToolbarScrollStart()
			})
		]
		var destroy = function() {
			each$1(listeners, function(l) {
				l.unbind()
			})
		}
		return { destroy: destroy }
	}

	function FakeSelection(win, frame) {
		var doc = win.document
		var container = SugarElement.fromTag('div')
		add$1(container, resolve('unfocused-selections'))
		append$2(SugarElement.fromDom(doc.documentElement), container)
		var onTouch = bind(container, 'touchstart', function(event) {
			event.prevent()
			resume(win, frame)
			clear()
		})
		var make = function(rectangle) {
			var span = SugarElement.fromTag('span')
			add(span, [resolve('layer-editor'), resolve('unfocused-selection')])
			setAll(span, {
				left: rectangle.left + 'px',
				top: rectangle.top + 'px',
				width: rectangle.width + 'px',
				height: rectangle.height + 'px'
			})
			return span
		}
		var update = function() {
			clear()
			var rectangles = getRectangles(win)
			var spans = map$2(rectangles, make)
			append$1(container, spans)
		}
		var clear = function() {
			empty(container)
		}
		var destroy = function() {
			onTouch.unbind()
			remove$7(container)
		}
		var isActive = function() {
			return children(container).length > 0
		}
		return {
			update: update,
			isActive: isActive,
			destroy: destroy,
			clear: clear
		}
	}

	var nu$1 = function(baseFn) {
		var data = Optional.none()
		var callbacks = []
		var map = function(f) {
			return nu$1(function(nCallback) {
				get(function(data) {
					nCallback(f(data))
				})
			})
		}
		var get = function(nCallback) {
			if (isReady()) {
				call(nCallback)
			} else {
				callbacks.push(nCallback)
			}
		}
		var set = function(x) {
			if (!isReady()) {
				data = Optional.some(x)
				run(callbacks)
				callbacks = []
			}
		}
		var isReady = function() {
			return data.isSome()
		}
		var run = function(cbs) {
			each$1(cbs, call)
		}
		var call = function(cb) {
			data.each(function(x) {
				setTimeout(function() {
					cb(x)
				}, 0)
			})
		}
		baseFn(set)
		return {
			get: get,
			map: map,
			isReady: isReady
		}
	}
	var pure$1 = function(a) {
		return nu$1(function(callback) {
			callback(a)
		})
	}
	var LazyValue = {
		nu: nu$1,
		pure: pure$1
	}

	var errorReporter = function(err) {
		setTimeout(function() {
			throw err
		}, 0)
	}
	var make = function(run) {
		var get = function(callback) {
			run().then(callback, errorReporter)
		}
		var map = function(fab) {
			return make(function() {
				return run().then(fab)
			})
		}
		var bind = function(aFutureB) {
			return make(function() {
				return run().then(function(v) {
					return aFutureB(v).toPromise()
				})
			})
		}
		var anonBind = function(futureB) {
			return make(function() {
				return run().then(function() {
					return futureB.toPromise()
				})
			})
		}
		var toLazy = function() {
			return LazyValue.nu(get)
		}
		var toCached = function() {
			var cache = null
			return make(function() {
				if (cache === null) {
					cache = run()
				}
				return cache
			})
		}
		var toPromise = run
		return {
			map: map,
			bind: bind,
			anonBind: anonBind,
			toLazy: toLazy,
			toCached: toCached,
			toPromise: toPromise,
			get: get
		}
	}
	var nu = function(baseFn) {
		return make(function() {
			return new Promise$1(baseFn)
		})
	}
	var pure = function(a) {
		return make(function() {
			return Promise$1.resolve(a)
		})
	}
	var Future = {
		nu: nu,
		pure: pure
	}

	var adjust = function(value, destination, amount) {
		if (Math.abs(value - destination) <= amount) {
			return Optional.none()
		} else if (value < destination) {
			return Optional.some(value + amount)
		} else {
			return Optional.some(value - amount)
		}
	}
	var create$1 = function() {
		var interval = null
		var animate = function(getCurrent, destination, amount, increment, doFinish, rate) {
			var finished = false
			var finish = function(v) {
				finished = true
				doFinish(v)
			}
			global$2.clearInterval(interval)
			var abort = function(v) {
				global$2.clearInterval(interval)
				finish(v)
			}
			interval = global$2.setInterval(function() {
				var value = getCurrent()
				adjust(value, destination, amount).fold(
					function() {
						global$2.clearInterval(interval)
						finish(destination)
					},
					function(s) {
						increment(s, abort)
						if (!finished) {
							var newValue = getCurrent()
							if (newValue !== s || Math.abs(newValue - destination) > Math.abs(value - destination)) {
								global$2.clearInterval(interval)
								finish(destination)
							}
						}
					}
				)
			}, rate)
		}
		return { animate: animate }
	}

	var findDevice = function(deviceWidth, deviceHeight) {
		var devices = [
			{
				width: 320,
				height: 480,
				keyboard: {
					portrait: 300,
					landscape: 240
				}
			},
			{
				width: 320,
				height: 568,
				keyboard: {
					portrait: 300,
					landscape: 240
				}
			},
			{
				width: 375,
				height: 667,
				keyboard: {
					portrait: 305,
					landscape: 240
				}
			},
			{
				width: 414,
				height: 736,
				keyboard: {
					portrait: 320,
					landscape: 240
				}
			},
			{
				width: 768,
				height: 1024,
				keyboard: {
					portrait: 320,
					landscape: 400
				}
			},
			{
				width: 1024,
				height: 1366,
				keyboard: {
					portrait: 380,
					landscape: 460
				}
			}
		]
		return findMap(devices, function(device) {
			return someIf(deviceWidth <= device.width && deviceHeight <= device.height, device.keyboard)
		}).getOr({
			portrait: deviceHeight / 5,
			landscape: deviceWidth / 4
		})
	}

	var softKeyboardLimits = function(outerWindow) {
		return findDevice(outerWindow.screen.width, outerWindow.screen.height)
	}
	var accountableKeyboardHeight = function(outerWindow) {
		var portrait = get$1(outerWindow).isPortrait()
		var limits = softKeyboardLimits(outerWindow)
		var keyboard = portrait ? limits.portrait : limits.landscape
		var visualScreenHeight = portrait ? outerWindow.screen.height : outerWindow.screen.width
		return visualScreenHeight - outerWindow.innerHeight > keyboard ? 0 : keyboard
	}
	var getGreenzone = function(socket, dropup) {
		var outerWindow = owner$2(socket).dom.defaultView
		var viewportHeight = get$7(socket) + get$7(dropup)
		var acc = accountableKeyboardHeight(outerWindow)
		return viewportHeight - acc
	}
	var updatePadding = function(contentBody, socket, dropup) {
		var greenzoneHeight = getGreenzone(socket, dropup)
		var deltaHeight = get$7(socket) + get$7(dropup) - greenzoneHeight
		set$5(contentBody, 'padding-bottom', deltaHeight + 'px')
	}

	var fixture = Adt.generate([
		{
			fixed: ['element', 'property', 'offsetY']
		},
		{
			scroller: ['element', 'offsetY']
		}
	])
	var yFixedData = 'data-' + resolve('position-y-fixed')
	var yFixedProperty = 'data-' + resolve('y-property')
	var yScrollingData = 'data-' + resolve('scrolling')
	var windowSizeData = 'data-' + resolve('last-window-height')
	var getYFixedData = function(element) {
		return safeParse(element, yFixedData)
	}
	var getYFixedProperty = function(element) {
		return get$b(element, yFixedProperty)
	}
	var getLastWindowSize = function(element) {
		return safeParse(element, windowSizeData)
	}
	var classifyFixed = function(element, offsetY) {
		var prop = getYFixedProperty(element)
		return fixture.fixed(element, prop, offsetY)
	}
	var classifyScrolling = function(element, offsetY) {
		return fixture.scroller(element, offsetY)
	}
	var classify = function(element) {
		var offsetY = getYFixedData(element)
		var classifier = get$b(element, yScrollingData) === 'true' ? classifyScrolling : classifyFixed
		return classifier(element, offsetY)
	}
	var findFixtures = function(container) {
		var candidates = descendants(container, '[' + yFixedData + ']')
		return map$2(candidates, classify)
	}
	var takeoverToolbar = function(toolbar) {
		var oldToolbarStyle = get$b(toolbar, 'style')
		setAll(toolbar, {
			position: 'absolute',
			top: '0px'
		})
		set$8(toolbar, yFixedData, '0px')
		set$8(toolbar, yFixedProperty, 'top')
		var restore = function() {
			set$8(toolbar, 'style', oldToolbarStyle || '')
			remove$6(toolbar, yFixedData)
			remove$6(toolbar, yFixedProperty)
		}
		return { restore: restore }
	}
	var takeoverViewport = function(toolbarHeight, height, viewport) {
		var oldViewportStyle = get$b(viewport, 'style')
		register$2(viewport)
		setAll(viewport, {
			position: 'absolute',
			height: height + 'px',
			width: '100%',
			top: toolbarHeight + 'px'
		})
		set$8(viewport, yFixedData, toolbarHeight + 'px')
		set$8(viewport, yScrollingData, 'true')
		set$8(viewport, yFixedProperty, 'top')
		var restore = function() {
			deregister(viewport)
			set$8(viewport, 'style', oldViewportStyle || '')
			remove$6(viewport, yFixedData)
			remove$6(viewport, yScrollingData)
			remove$6(viewport, yFixedProperty)
		}
		return { restore: restore }
	}
	var takeoverDropup = function(dropup) {
		var oldDropupStyle = get$b(dropup, 'style')
		setAll(dropup, {
			position: 'absolute',
			bottom: '0px'
		})
		set$8(dropup, yFixedData, '0px')
		set$8(dropup, yFixedProperty, 'bottom')
		var restore = function() {
			set$8(dropup, 'style', oldDropupStyle || '')
			remove$6(dropup, yFixedData)
			remove$6(dropup, yFixedProperty)
		}
		return { restore: restore }
	}
	var deriveViewportHeight = function(viewport, toolbarHeight, dropupHeight) {
		var outerWindow = owner$2(viewport).dom.defaultView
		var winH = outerWindow.innerHeight
		set$8(viewport, windowSizeData, winH + 'px')
		return winH - toolbarHeight - dropupHeight
	}
	var takeover = function(viewport, contentBody, toolbar, dropup) {
		var outerWindow = owner$2(viewport).dom.defaultView
		var toolbarSetup = takeoverToolbar(toolbar)
		var toolbarHeight = get$7(toolbar)
		var dropupHeight = get$7(dropup)
		var viewportHeight = deriveViewportHeight(viewport, toolbarHeight, dropupHeight)
		var viewportSetup = takeoverViewport(toolbarHeight, viewportHeight, viewport)
		var dropupSetup = takeoverDropup(dropup)
		var isActive = true
		var restore = function() {
			isActive = false
			toolbarSetup.restore()
			viewportSetup.restore()
			dropupSetup.restore()
		}
		var isExpanding = function() {
			var currentWinHeight = outerWindow.innerHeight
			var lastWinHeight = getLastWindowSize(viewport)
			return currentWinHeight > lastWinHeight
		}
		var refresh = function() {
			if (isActive) {
				var newToolbarHeight = get$7(toolbar)
				var dropupHeight_1 = get$7(dropup)
				var newHeight = deriveViewportHeight(viewport, newToolbarHeight, dropupHeight_1)
				set$8(viewport, yFixedData, newToolbarHeight + 'px')
				set$5(viewport, 'height', newHeight + 'px')
				updatePadding(contentBody, viewport, dropup)
			}
		}
		var setViewportOffset = function(newYOffset) {
			var offsetPx = newYOffset + 'px'
			set$8(viewport, yFixedData, offsetPx)
			refresh()
		}
		updatePadding(contentBody, viewport, dropup)
		return {
			setViewportOffset: setViewportOffset,
			isExpanding: isExpanding,
			isShrinking: not(isExpanding),
			refresh: refresh,
			restore: restore
		}
	}

	var animator = create$1()
	var ANIMATION_STEP = 15
	var NUM_TOP_ANIMATION_FRAMES = 10
	var ANIMATION_RATE = 10
	var lastScroll = 'data-' + resolve('last-scroll-top')
	var getTop = function(element) {
		var raw = getRaw(element, 'top').getOr('0')
		return parseInt(raw, 10)
	}
	var getScrollTop = function(element) {
		return parseInt(element.dom.scrollTop, 10)
	}
	var moveScrollAndTop = function(element, destination, finalTop) {
		return Future.nu(function(callback) {
			var getCurrent = curry(getScrollTop, element)
			var update = function(newScroll) {
				element.dom.scrollTop = newScroll
				set$5(element, 'top', getTop(element) + ANIMATION_STEP + 'px')
			}
			var finish = function() {
				element.dom.scrollTop = destination
				set$5(element, 'top', finalTop + 'px')
				callback(destination)
			}
			animator.animate(getCurrent, destination, ANIMATION_STEP, update, finish, ANIMATION_RATE)
		})
	}
	var moveOnlyScroll = function(element, destination) {
		return Future.nu(function(callback) {
			var getCurrent = curry(getScrollTop, element)
			set$8(element, lastScroll, getCurrent())
			var update = function(newScroll, abort) {
				var previous = safeParse(element, lastScroll)
				if (previous !== element.dom.scrollTop) {
					abort(element.dom.scrollTop)
				} else {
					element.dom.scrollTop = newScroll
					set$8(element, lastScroll, newScroll)
				}
			}
			var finish = function() {
				element.dom.scrollTop = destination
				set$8(element, lastScroll, destination)
				callback(destination)
			}
			var distance = Math.abs(destination - getCurrent())
			var step = Math.ceil(distance / NUM_TOP_ANIMATION_FRAMES)
			animator.animate(getCurrent, destination, step, update, finish, ANIMATION_RATE)
		})
	}
	var moveOnlyTop = function(element, destination) {
		return Future.nu(function(callback) {
			var getCurrent = curry(getTop, element)
			var update = function(newTop) {
				set$5(element, 'top', newTop + 'px')
			}
			var finish = function() {
				update(destination)
				callback(destination)
			}
			var distance = Math.abs(destination - getCurrent())
			var step = Math.ceil(distance / NUM_TOP_ANIMATION_FRAMES)
			animator.animate(getCurrent, destination, step, update, finish, ANIMATION_RATE)
		})
	}
	var updateTop = function(element, amount) {
		var newTop = amount + getYFixedData(element) + 'px'
		set$5(element, 'top', newTop)
	}
	var moveWindowScroll = function(toolbar, viewport, destY) {
		var outerWindow = owner$2(toolbar).dom.defaultView
		return Future.nu(function(callback) {
			updateTop(toolbar, destY)
			updateTop(viewport, destY)
			outerWindow.scrollTo(0, destY)
			callback(destY)
		})
	}

	function BackgroundActivity(doAction) {
		var action = Cell(LazyValue.pure({}))
		var start = function(value) {
			var future = LazyValue.nu(function(callback) {
				return doAction(value).get(callback)
			})
			action.set(future)
		}
		var idle = function(g) {
			action.get().get(function() {
				g()
			})
		}
		return {
			start: start,
			idle: idle
		}
	}

	var scrollIntoView = function(cWin, socket, dropup, top, bottom) {
		var greenzone = getGreenzone(socket, dropup)
		var refreshCursor = curry(refresh, cWin)
		if (top > greenzone || bottom > greenzone) {
			moveOnlyScroll(socket, socket.dom.scrollTop - greenzone + bottom).get(refreshCursor)
		} else if (top < 0) {
			moveOnlyScroll(socket, socket.dom.scrollTop + top).get(refreshCursor)
		} else;
	}

	var par$1 = function(asyncValues, nu) {
		return nu(function(callback) {
			var r = []
			var count = 0
			var cb = function(i) {
				return function(value) {
					r[i] = value
					count++
					if (count >= asyncValues.length) {
						callback(r)
					}
				}
			}
			if (asyncValues.length === 0) {
				callback([])
			} else {
				each$1(asyncValues, function(asyncValue, i) {
					asyncValue.get(cb(i))
				})
			}
		})
	}

	var par = function(futures) {
		return par$1(futures, Future.nu)
	}

	var updateFixed = function(element, property, winY, offsetY) {
		var destination = winY + offsetY
		set$5(element, property, destination + 'px')
		return Future.pure(offsetY)
	}
	var updateScrollingFixed = function(element, winY, offsetY) {
		var destTop = winY + offsetY
		var oldProp = getRaw(element, 'top').getOr(offsetY)
		var delta = destTop - parseInt(oldProp, 10)
		var destScroll = element.dom.scrollTop + delta
		return moveScrollAndTop(element, destScroll, destTop)
	}
	var updateFixture = function(fixture, winY) {
		return fixture.fold(
			function(element, property, offsetY) {
				return updateFixed(element, property, winY, offsetY)
			},
			function(element, offsetY) {
				return updateScrollingFixed(element, winY, offsetY)
			}
		)
	}
	var updatePositions = function(container, winY) {
		var fixtures = findFixtures(container)
		var updates = map$2(fixtures, function(fixture) {
			return updateFixture(fixture, winY)
		})
		return par(updates)
	}

	var VIEW_MARGIN = 5
	var register = function(toolstrip, socket, container, outerWindow, structure, cWin) {
		var scroller = BackgroundActivity(function(y) {
			return moveWindowScroll(toolstrip, socket, y)
		})
		var scrollBounds = function() {
			var rects = getRectangles(cWin)
			return Optional.from(rects[0]).bind(function(rect) {
				var viewTop = rect.top - socket.dom.scrollTop
				var outside = viewTop > outerWindow.innerHeight + VIEW_MARGIN || viewTop < -VIEW_MARGIN
				return outside
					? Optional.some({
							top: viewTop,
							bottom: viewTop + rect.height
					  })
					: Optional.none()
			})
		}
		var scrollThrottle = last(function() {
			scroller.idle(function() {
				updatePositions(container, outerWindow.pageYOffset).get(function() {
					var extraScroll = scrollBounds()
					extraScroll.each(function(extra) {
						socket.dom.scrollTop = socket.dom.scrollTop + extra.top
					})
					scroller.start(0)
					structure.refresh()
				})
			})
		}, 1000)
		var onScroll = bind(SugarElement.fromDom(outerWindow), 'scroll', function() {
			if (outerWindow.pageYOffset < 0) {
				return
			}
			scrollThrottle.throttle()
		})
		updatePositions(container, outerWindow.pageYOffset).get(identity)
		return { unbind: onScroll.unbind }
	}
	var setup = function(bag) {
		var cWin = bag.cWin
		var ceBody = bag.ceBody
		var socket = bag.socket
		var toolstrip = bag.toolstrip
		var contentElement = bag.contentElement
		var keyboardType = bag.keyboardType
		var outerWindow = bag.outerWindow
		var dropup = bag.dropup
		var outerBody = bag.outerBody
		var structure = takeover(socket, ceBody, toolstrip, dropup)
		var keyboardModel = keyboardType(outerBody, cWin, body(), contentElement)
		var toEditing = function() {
			keyboardModel.toEditing()
			clearSelection()
		}
		var toReading = function() {
			keyboardModel.toReading()
		}
		var onToolbarTouch = function(_event) {
			keyboardModel.onToolbarTouch()
		}
		var onOrientation = onChange(outerWindow, {
			onChange: noop,
			onReady: structure.refresh
		})
		onOrientation.onAdjustment(function() {
			structure.refresh()
		})
		var onResize = bind(SugarElement.fromDom(outerWindow), 'resize', function() {
			if (structure.isExpanding()) {
				structure.refresh()
			}
		})
		var onScroll = register(toolstrip, socket, outerBody, outerWindow, structure, cWin)
		var unfocusedSelection = FakeSelection(cWin, contentElement)
		var refreshSelection = function() {
			if (unfocusedSelection.isActive()) {
				unfocusedSelection.update()
			}
		}
		var highlightSelection = function() {
			unfocusedSelection.update()
		}
		var clearSelection = function() {
			unfocusedSelection.clear()
		}
		var scrollIntoView$1 = function(top, bottom) {
			scrollIntoView(cWin, socket, dropup, top, bottom)
		}
		var syncHeight = function() {
			set$5(contentElement, 'height', contentElement.dom.contentWindow.document.body.scrollHeight + 'px')
		}
		var setViewportOffset = function(newYOffset) {
			structure.setViewportOffset(newYOffset)
			moveOnlyTop(socket, newYOffset).get(identity)
		}
		var destroy = function() {
			structure.restore()
			onOrientation.destroy()
			onScroll.unbind()
			onResize.unbind()
			keyboardModel.destroy()
			unfocusedSelection.destroy()
			input(body(), blur$1)
		}
		return {
			toEditing: toEditing,
			toReading: toReading,
			onToolbarTouch: onToolbarTouch,
			refreshSelection: refreshSelection,
			clearSelection: clearSelection,
			highlightSelection: highlightSelection,
			scrollIntoView: scrollIntoView$1,
			updateToolbarPadding: noop,
			setViewportOffset: setViewportOffset,
			syncHeight: syncHeight,
			refreshStructure: structure.refresh,
			destroy: destroy
		}
	}

	var create = function(platform, mask) {
		var meta = tag()
		var priorState = value()
		var scrollEvents = value()
		var iosApi = api$2()
		var iosEvents = api$2()
		var enter = function() {
			mask.hide()
			var doc = SugarElement.fromDom(document)
			getActiveApi(platform.editor).each(function(editorApi) {
				priorState.set({
					socketHeight: getRaw(platform.socket, 'height'),
					iframeHeight: getRaw(editorApi.frame, 'height'),
					outerScroll: document.body.scrollTop
				})
				scrollEvents.set({ exclusives: exclusive(doc, '.' + scrollable) })
				add$1(platform.container, resolve('fullscreen-maximized'))
				clobberStyles(platform.container, editorApi.body)
				meta.maximize()
				set$5(platform.socket, 'overflow', 'scroll')
				set$5(platform.socket, '-webkit-overflow-scrolling', 'touch')
				focus$3(editorApi.body)
				iosApi.set(
					setup({
						cWin: editorApi.win,
						ceBody: editorApi.body,
						socket: platform.socket,
						toolstrip: platform.toolstrip,
						dropup: platform.dropup.element,
						contentElement: editorApi.frame,
						outerBody: platform.body,
						outerWindow: platform.win,
						keyboardType: stubborn
					})
				)
				iosApi.run(function(api) {
					api.syncHeight()
				})
				iosEvents.set(initEvents(editorApi, iosApi, platform.toolstrip, platform.socket, platform.dropup))
			})
		}
		var exit = function() {
			meta.restore()
			iosEvents.clear()
			iosApi.clear()
			mask.show()
			priorState.on(function(s) {
				s.socketHeight.each(function(h) {
					set$5(platform.socket, 'height', h)
				})
				s.iframeHeight.each(function(h) {
					set$5(platform.editor.getFrame(), 'height', h)
				})
				document.body.scrollTop = s.scrollTop
			})
			priorState.clear()
			scrollEvents.on(function(s) {
				s.exclusives.unbind()
			})
			scrollEvents.clear()
			remove$3(platform.container, resolve('fullscreen-maximized'))
			restoreStyles()
			deregister(platform.toolbar)
			remove$2(platform.socket, 'overflow')
			remove$2(platform.socket, '-webkit-overflow-scrolling')
			blur$1(platform.editor.getFrame())
			getActiveApi(platform.editor).each(function(editorApi) {
				editorApi.clearSelection()
			})
		}
		var refreshStructure = function() {
			iosApi.run(function(api) {
				api.refreshStructure()
			})
		}
		return {
			enter: enter,
			refreshStructure: refreshStructure,
			exit: exit
		}
	}

	var produce = function(raw) {
		var mobile = asRawOrDie$1('Getting IosWebapp schema', MobileSchema, raw)
		set$5(mobile.toolstrip, 'width', '100%')
		set$5(mobile.container, 'position', 'relative')
		var onView = function() {
			mobile.setReadOnly(mobile.readOnlyOnInit())
			mode.enter()
		}
		var mask = build$1(sketch(onView, mobile.translate))
		mobile.alloy.add(mask)
		var maskApi = {
			show: function() {
				mobile.alloy.add(mask)
			},
			hide: function() {
				mobile.alloy.remove(mask)
			}
		}
		var mode = create(mobile, maskApi)
		return {
			setReadOnly: mobile.setReadOnly,
			refreshStructure: mode.refreshStructure,
			enter: mode.enter,
			exit: mode.exit,
			destroy: noop
		}
	}

	function IosRealm(scrollIntoView) {
		var alloy = OuterContainer({ classes: [resolve('ios-container')] })
		var toolbar = ScrollingToolbar()
		var webapp = api$2()
		var switchToEdit = makeEditSwitch(webapp)
		var socket = makeSocket()
		var dropup = build(function() {
			webapp.run(function(w) {
				w.refreshStructure()
			})
		}, scrollIntoView)
		alloy.add(toolbar.wrapper)
		alloy.add(socket)
		alloy.add(dropup.component)
		var setToolbarGroups = function(rawGroups) {
			var groups = toolbar.createGroups(rawGroups)
			toolbar.setGroups(groups)
		}
		var setContextToolbar = function(rawGroups) {
			var groups = toolbar.createGroups(rawGroups)
			toolbar.setContextToolbar(groups)
		}
		var focusToolbar = function() {
			toolbar.focus()
		}
		var restoreToolbar = function() {
			toolbar.restoreToolbar()
		}
		var init = function(spec) {
			webapp.set(produce(spec))
		}
		var exit = function() {
			webapp.run(function(w) {
				Replacing.remove(socket, switchToEdit)
				w.exit()
			})
		}
		var updateMode$1 = function(readOnly) {
			updateMode(socket, switchToEdit, readOnly, alloy.root)
		}
		return {
			system: alloy,
			element: alloy.element,
			init: init,
			exit: exit,
			setToolbarGroups: setToolbarGroups,
			setContextToolbar: setContextToolbar,
			focusToolbar: focusToolbar,
			restoreToolbar: restoreToolbar,
			updateMode: updateMode$1,
			socket: socket,
			dropup: dropup
		}
	}

	var global$1 = tinymce.util.Tools.resolve('tinymce.EditorManager')

	var derive = function(editor) {
		var base = Optional.from(getSkinUrl(editor)).getOrThunk(function() {
			return global$1.baseURL + '/skins/ui/oxide'
		})
		return {
			content: base + '/content.mobile.min.css',
			ui: base + '/skin.mobile.min.css'
		}
	}

	var fireChange = function(realm, command, state) {
		realm.system.broadcastOn([formatChanged], {
			command: command,
			state: state
		})
	}
	var init = function(realm, editor) {
		var allFormats = keys(editor.formatter.get())
		each$1(allFormats, function(command) {
			editor.formatter.formatChanged(command, function(state) {
				fireChange(realm, command, state)
			})
		})
		each$1(['ul', 'ol'], function(command) {
			editor.selection.selectorChanged(command, function(state, _data) {
				fireChange(realm, command, state)
			})
		})
	}

	var fireSkinLoaded = function(editor) {
		return function() {
			var done = function() {
				editor._skinLoaded = true
				editor.fire('SkinLoaded')
			}
			if (editor.initialized) {
				done()
			} else {
				editor.on('init', done)
			}
		}
	}

	var READING = 'toReading'
	var EDITING = 'toEditing'
	var renderMobileTheme = function(editor) {
		var renderUI = function() {
			var targetNode = editor.getElement()
			var cssUrls = derive(editor)
			if (isSkinDisabled(editor) === false) {
				var styleSheetLoader_1 = global$5.DOM.styleSheetLoader
				editor.contentCSS.push(cssUrls.content)
				styleSheetLoader_1.load(cssUrls.ui, fireSkinLoaded(editor))
				editor.on('remove', function() {
					return styleSheetLoader_1.unload(cssUrls.ui)
				})
			} else {
				fireSkinLoaded(editor)()
			}
			var doScrollIntoView = function() {
				editor.fire('ScrollIntoView')
			}
			var realm = detect$1().os.isAndroid() ? AndroidRealm(doScrollIntoView) : IosRealm(doScrollIntoView)
			var original = SugarElement.fromDom(targetNode)
			attachSystemAfter(original, realm.system)
			var findFocusIn = function(elem) {
				return search(elem).bind(function(focused) {
					return realm.system.getByDom(focused).toOptional()
				})
			}
			var outerWindow = targetNode.ownerDocument.defaultView
			var orientation = onChange(outerWindow, {
				onChange: function() {
					var alloy = realm.system
					alloy.broadcastOn([orientationChanged], { width: getActualWidth(outerWindow) })
				},
				onReady: noop
			})
			var setReadOnly = function(dynamicGroup, readOnlyGroups, mainGroups, ro) {
				if (ro === false) {
					editor.selection.collapse()
				}
				var toolbars = configureToolbar(dynamicGroup, readOnlyGroups, mainGroups)
				realm.setToolbarGroups(ro === true ? toolbars.readOnly : toolbars.main)
				editor.setMode(ro === true ? 'readonly' : 'design')
				editor.fire(ro === true ? READING : EDITING)
				realm.updateMode(ro)
			}
			var configureToolbar = function(dynamicGroup, readOnlyGroups, mainGroups) {
				var dynamic = dynamicGroup.get()
				var toolbars = {
					readOnly: dynamic.backToMask.concat(readOnlyGroups.get()),
					main: dynamic.backToMask.concat(mainGroups.get())
				}
				return toolbars
			}
			var bindHandler = function(label, handler) {
				editor.on(label, handler)
				return {
					unbind: function() {
						editor.off(label)
					}
				}
			}
			editor.on('init', function() {
				realm.init({
					editor: {
						getFrame: function() {
							return SugarElement.fromDom(editor.contentAreaContainer.querySelector('iframe'))
						},
						onDomChanged: function() {
							return { unbind: noop }
						},
						onToReading: function(handler) {
							return bindHandler(READING, handler)
						},
						onToEditing: function(handler) {
							return bindHandler(EDITING, handler)
						},
						onScrollToCursor: function(handler) {
							editor.on('ScrollIntoView', function(tinyEvent) {
								handler(tinyEvent)
							})
							var unbind = function() {
								editor.off('ScrollIntoView')
								orientation.destroy()
							}
							return { unbind: unbind }
						},
						onTouchToolstrip: function() {
							hideDropup()
						},
						onTouchContent: function() {
							var toolbar = SugarElement.fromDom(
								editor.editorContainer.querySelector('.' + resolve('toolbar'))
							)
							findFocusIn(toolbar).each(emitExecute)
							realm.restoreToolbar()
							hideDropup()
						},
						onTapContent: function(evt) {
							var target = evt.target
							if (name$1(target) === 'img') {
								editor.selection.select(target.dom)
								evt.kill()
							} else if (name$1(target) === 'a') {
								var component = realm.system.getByDom(SugarElement.fromDom(editor.editorContainer))
								component.each(function(container) {
									if (Swapping.isAlpha(container)) {
										openLink(target.dom)
									}
								})
							}
						}
					},
					container: SugarElement.fromDom(editor.editorContainer),
					socket: SugarElement.fromDom(editor.contentAreaContainer),
					toolstrip: SugarElement.fromDom(editor.editorContainer.querySelector('.' + resolve('toolstrip'))),
					toolbar: SugarElement.fromDom(editor.editorContainer.querySelector('.' + resolve('toolbar'))),
					dropup: realm.dropup,
					alloy: realm.system,
					translate: noop,
					setReadOnly: function(ro) {
						setReadOnly(dynamicGroup, readOnlyGroups, mainGroups, ro)
					},
					readOnlyOnInit: function() {
						return readOnlyOnInit()
					}
				})
				var hideDropup = function() {
					realm.dropup.disappear(function() {
						realm.system.broadcastOn([dropupDismissed], {})
					})
				}
				var backToMaskGroup = {
					label: 'The first group',
					scrollable: false,
					items: [
						forToolbar(
							'back',
							function() {
								editor.selection.collapse()
								realm.exit()
							},
							{},
							editor
						)
					]
				}
				var backToReadOnlyGroup = {
					label: 'Back to read only',
					scrollable: false,
					items: [
						forToolbar(
							'readonly-back',
							function() {
								setReadOnly(dynamicGroup, readOnlyGroups, mainGroups, true)
							},
							{},
							editor
						)
					]
				}
				var readOnlyGroup = {
					label: 'The read only mode group',
					scrollable: true,
					items: []
				}
				var features = setup$3(realm, editor)
				var items = detect(editor, features)
				var actionGroup = {
					label: 'the action group',
					scrollable: true,
					items: items
				}
				var extraGroup = {
					label: 'The extra group',
					scrollable: false,
					items: []
				}
				var mainGroups = Cell([actionGroup, extraGroup])
				var readOnlyGroups = Cell([readOnlyGroup, extraGroup])
				var dynamicGroup = Cell({
					backToMask: [backToMaskGroup],
					backToReadOnly: [backToReadOnlyGroup]
				})
				init(realm, editor)
			})
			editor.on('remove', function() {
				realm.exit()
			})
			editor.on('detach', function() {
				detachSystem(realm.system)
				realm.system.destroy()
			})
			return {
				iframeContainer: realm.socket.element.dom,
				editorContainer: realm.element.dom
			}
		}
		return {
			getNotificationManagerImpl: function() {
				return {
					open: constant$1({
						progressBar: { value: noop },
						close: noop,
						text: noop,
						getEl: constant$1(null),
						moveTo: noop,
						moveRel: noop,
						settings: {}
					}),
					close: noop,
					reposition: noop,
					getArgs: constant$1({})
				}
			},
			renderUI: renderUI
		}
	}
	function Theme() {
		global$4.add('mobile', renderMobileTheme)
	}

	Theme()
})()
